go - 为什么 Go 不能正确地杀死一个子进程?

标签 go exec

当 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")
}()

我不认为它应该有什么不同,但它的值(value)在于命令是 go test html。它超时的原因是因为我在运行它之前注入(inject)了一个导致无限循环的错误。为了增加困惑,我尝试使用 go test net 运行它。有一个超时,它工作正常。

最佳答案

看起来问题在于 cmd.Process.Kill() 不会终止子进程。看到这个类似的问题Process.Kill() on child processes

我在这个线程中找到了解决方案 https://groups.google.com/forum/#!topic/golang-nuts/XoQ3RhFBJl8

cmd := exec.Command( some_command )
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
cmd.Start()

pgid, err := syscall.Getpgid(cmd.Process.Pid)
if err == nil {
    syscall.Kill(-pgid, 15)  // note the minus sign
}

cmd.Wait()

作为一个警告,这几乎肯定不能跨平台工作——我目前在 OSX Yosemite 上,我敢打赌它也能在大多数 Linux 上工作,但我还不够了解关于 BSD 有意见,我怀疑它是否适用于 Windows。

关于go - 为什么 Go 不能正确地杀死一个子进程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22470193/

相关文章:

string - 如何将 Go 字符串文字代码转换为其值?

go - 为什么在 golang 中仅初始化定义中的一个变量会失败

Java process.start 如果父进程在启动后没有被销毁,速度会非常慢

python - exec() 在遇到 : character 时引发 'unexpected EOF' 错误

c - 如何用C代码编写shell '&'?

Php Exec 外部 python 脚本 - 权限被拒绝

php - Windows CMD.exe "The system cannot find the path specified."

google-app-engine - 使用 Google App Engine SDK 在 Go 中进行简单应用

go - 像 MySQL 格式一样以 RFC3339 格式输出 Go 时间

Golang Sprintf格式化字符串并多次使用