【发布时间】:2015-12-04 18:39:54
【问题描述】:
如果我(出于任何原因)退出父应用程序,我需要运行一个长时间运行的子进程并终止它。
代码如下:
cmd := exec.Command("./long-process")
defer cmd.Process.Kill()
if err != nil {
log.Fatal(err)
}
var fail io.ReadCloser
fail.Close()
这里的fail 很明显
panic: runtime error: invalid memory address or nil pointer dereference
它按预期工作 - 子进程被杀死。
但这发生在 goroutine 中:
cmd := exec.Command("./long-process")
defer cmd.Process.Kill()
if err != nil {
log.Fatal(err)
}
go func() {
var fail io.ReadCloser
fail.Close()
}()
恐慌仍然发生,但似乎 defer 没有被调用并且子进程没有被杀死。
有什么办法可以解决这个问题吗?
更新我需要一个跨平台的解决方案(至少对于 Linux 和 FreeBSD)
小例子:
infinite-loop.sh
#!/bin/bash
while true; do
sleep 1
done
别忘了
chmod +x infinite-loop.sh
test1.go(为简洁起见省略了错误检查):
package main
import (
"time"
"io"
"os/exec"
"runtime"
)
func main() {
cmd := exec.Command("./infinite-loop.sh")
cmd.Start()
defer cmd.Process.Kill()
go func() {
time.Sleep(100 * time.Millisecond)
var fail io.ReadCloser
fail.Close()
}()
for {
runtime.Gosched()
}
}
我们跑吧
ps aux | grep infinite-loop.sh | grep -v grep | wc -l; \
go run test1.go; \
ps aux | grep infinite-loop.sh | grep -v grep | wc -l
0 <--- !!
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x20 pc=0x2130]
goroutine 5 [running]:
main.main.func1()
.../multiline/test1.go:19 +0x30
created by main.main
.../multiline/test1.go:20 +0x9a
goroutine 1 [runnable]:
runtime.Gosched()
/usr/local/Cellar/go/1.5.1/libexec/src/runtime/proc.go:166 +0x14
main.main()
.../multiline/test1.go:23 +0x9f
exit status 2
1 <--- !!
退出前有 0 个进程,退出后有 1 个进程。
如果你注释掉 goroutine 代码 - 它工作正常。
现在我们可以杀死它了:
kill $(ps aux | grep infinite-loop.sh | grep -v grep | awk {'print $2'})
【问题讨论】:
-
你不想那样推迟,因为如果函数在 cmd 启动之前返回,Process 将为 nil,你会得到另一个恐慌。
-
@JimB 感谢您的通知!
-
@MarkusWMahlberg 已添加,谢谢!
标签: go