【发布时间】:2014-03-18 04:08:27
【问题描述】:
当 cmd 在分配的时间内完成时,以下工作正常。但是,超时不起作用。虽然它确实打印了"It's dead Jim",但它不仅无法打印"Done waiting",而且该进程实际上并没有被杀死。它继续运行,"Done waiting" 永远不会打印。
func() {
var output bytes.Buffer
cmd := exec.Command("Command", args...)
cmd.Dir = filepath.Dir(srcFile)
cmd.Stdout, cmd.Stderr = &output, &output
if err := cmd.Start(); err != nil {
return err
}
defer time.AfterFunc(time.Second*2, func() {
fmt.Printf("Nobody got time fo that\n")
if err := cmd.Process.Signal(syscall.SIGKILL); err != nil {
fmt.Printf("Error:%s\n", err)
}
fmt.Printf("It's dead Jim\n")
}).Stop()
err := cmd.Wait()
fmt.Printf("Done waiting\n")
}()
我不认为它应该有所作为,但对于它的价值来说,命令是go test html。它超时的原因是因为我在运行它之前注入了一个导致无限循环的错误。为了增加混乱,我尝试使用go test net 运行它。有一个超时,它工作正常。
【问题讨论】:
-
一个原因可能是
Kill()只向进程发送TERM信号,进程可以随意忽略或特殊处理。如果目标进程被阻塞(例如,它当前处于不可重新启动的系统调用中),也可能不会传递信号。可以肯定的是,让Kill()发送KILL信号。 -
@kostix,感谢您指出这一点。 documentation 相当含糊。我现在明确发送 SIGKILL,但它仍然无法正常工作。
-
因为
SIGKILL肯定会终止进程(除非它以某种方式严重楔入)我倾向于认为还有其他问题。在您的真实代码中,您是否检查对os.Process.Kill()的调用是否有错误? -
从 Go 1.7 开始,为孩子提供取消或超时的首选方式是使用
exec.CommandContext并安排取消或超时上下文。 -
Kill() 发送 SIGKILL,不能被捕获或忽略。见this answer。在上下文中调用取消也会发送 SIGKILL。