Golang: Child Processes become Zombies

2019-04-25 07:36发布

问题:

I have an application in Go that reroutes the STDIN and STDOUT of binaries and then runs them. In a nutshell I'm doing:

- create command object with the binary path (lets call the object command A) - create command object with the binary path (calling it command B) - set the stdout of command B to the stdin of Command A - start command A - start command B

I noticed whenever the process for command B exits while command A is running, it becomes a zombie process in the process table.

Here's an example:

commandA := exec.Command("samplebin")
commandB := exec.Command("sample2bin")

cmdAStdin := commandA.StdinPipe()

commandB.Stdout = cmdAStdin

commandA.Start()
commandB.Start()

Why does commandB become a Zombie if it exits while commandA is still running? I'm running Go 1.5 on Ubuntu 14.

回答1:

When a process exits, it ALWAYS becomes a zombie, regardless of what other processes are running. That's just the way process termination works. The process will remain a zombie until its parent calls wait to get its exit status, or indicates that it is uninterested in children by ignoring SIGCHLD (which may have been before the child exited). It will remain a zombie until that happens, lest the exit status get lost.

In your example, it would seem that your process (the one creating the processes) is the parent, so both A and B will remain as zombies until your process collects them.

If a process exits while it still has children (either running or zombies), those children will be reparented to the exiting process's parent, which will generally ignore the exit status (clearing up the zombies).



回答2:

Agree with the first answer that exiting processes becomes zombies until the process is waited for by another process. Here's how I handle things in go.

package main

import (
    "bytes"
    "io"
    "os"
    "os/exec"
)

func main() {
    c1 := exec.Command("samplebin")
    c2 := exec.Command("sample2bin")

    r, w := io.Pipe()
    c1.Stdout = w
    c2.Stdin = r

    var b2 bytes.Buffer
    c2.Stdout = &b2

    // Writing without a reader will deadlock so write in a goroutine
    go func() {
        // Close the writer or the pipe will not be closed for c2
        defer w.Close()
        defer c1.Wait()
        c1.Start()
    }()
    defer c2.Wait()
    c2.Start()
    io.Copy(os.Stdout, &b2)
}