Why won't Go kill a child process correctly?

后端 未结 5 544
小蘑菇
小蘑菇 2020-12-14 23:43

The following works just fine when cmd finishes in the allotted time. However, the timeout is not working. While it does print \"It\'s dead Jim\", not only do

5条回答
  •  Happy的楠姐
    2020-12-15 00:35

    Go's defer statement schedules a function call (the deferred function) to be run immediately before the function executing the defer returns.

    So the things after defer

    defer time.AfterFunc(time.Second*2, func() {
        fmt.Printf("Nobody got time fo that\n")
        cmd.Process.Kill()
        fmt.Printf("It's dead Jim\n")
    }).Stop()
    

    wouldn't be executed unless func() ends. Therefore, if "cmd.Wait()" never end, the "time.AfterFunc()" is never executed.

    Removing "time.AfterFunc(...)" from defer can fix this problem, since "time.AfterFunc" could waits for the duration to elapse and then calls f in its own goroutine.

    Here is a working version. I tested in my ubuntu box and it works. Save source as wait.go

    package main
    
    import "os/exec"
    import "time"
    import "bytes"
    import "fmt"
    
    
    func main() {
        var output bytes.Buffer
            cmd := exec.Command("sleep", "10s")
            cmd.Stdout, cmd.Stderr = &output, &output
            if err := cmd.Start(); err != nil {
                    fmt.Printf("command start error\n")
                    return
            }
            time.AfterFunc(time.Second*2, func() {
                    fmt.Printf("Nobody got time for that\n")
                    cmd.Process.Kill()
                    fmt.Printf("It's dead Jim\n")
            })
            cmd.Wait()
            fmt.Printf("Done waiting\n")
    }
    

    Run the command:

    time go run wait.go
    

    Output:

    Nobody got time for that
    It's dead Jim
    Done waiting
    
    real    0m2.481s
    user    0m0.252s
    sys 0m0.452s
    

    As @James Henstridge has commented that the above understanding is incorrect. Actually I had incomplete understanding of defer. The other half is "The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes". So the timer is truly created when defer is executed and thus timer will time out.

    The problem is really why the process cannot be killed. I checked the go's pkg's code, it sends a SIGKILL in *nix like system to kill the process. The SIGKILL cannot be blocked and ignored. So it could be other possibilites such as the process itself is in TASK_UNINTERRUPTIBLE state.

提交回复
热议问题