【问题标题】:Golang: Child Processes become ZombiesGolang:子进程变成僵尸
【发布时间】:2016-07-03 04:59:33
【问题描述】:

我在 Go 中有一个应用程序,它重新路由二进制文件的 STDIN 和 STDOUT,然后运行它们。简而言之,我正在做:

- 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

我注意到,每当命令 B 的进程在命令 A 运行时退出时,它就会成为进程表中的僵尸进程。

这是一个例子:

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

cmdAStdin := commandA.StdinPipe()

commandB.Stdout = cmdAStdin

commandA.Start()
commandB.Start()

如果 commandB 在 commandA 仍在运行时退出,为什么它会变成僵尸?我在 Ubuntu 14 上运行 Go 1.5。

【问题讨论】:

  • @chris-dodd 说的对,如果你只是不想要僵尸,你可以通过添加代码来忽略 SIGCHLD:signal.Ignore(syscall.SIGCHLD)

标签: go process stdout stdin zombie-process


【解决方案1】:

当一个进程退出时,它总是变成僵尸,不管其他进程正在运行。这就是进程终止的工作方式。该进程将保持僵尸状态,直到其父进程调用wait 以获取其退出状态,或者通过忽略 SIGCHLD(可能在子进程退出之前)表明它对子进程不感兴趣。在此之前它会一直保持僵尸状态,以免退出状态丢失。

在您的示例中,您的进程(创建进程的进程)似乎是父进程,因此在您的进程收集它们之前,A 和 B 都将保持为僵尸。

如果进程退出时仍有子进程(运行中或僵尸进程),这些子进程将重新设置为退出进程的父进程,父进程通常会忽略退出状态(清除僵尸进程)。

【讨论】:

  • 那么,SIGCHLD 是由子进程在它们成为僵尸之前发送的吗?那么如何“忽略” SIGCHLD?通过捕捉信号而无所作为?
  • SIGCHLD 由内核发送,当孩子成为僵尸的一部分时。如果您想忽略 SIGCHLD 并仍然得到僵尸,请将 SIGCHLD 操作设置为 SIG_DFL(默认值)而不是 SIG_IGN - 默认操作是什么都不做,但仍然会得到僵尸。
  • 我不想要僵尸,我想要清理退出的进程。我尝试在主应用程序中设置信号以忽略 SIGCHLD,但这仍然会造成僵尸,所以我最终调用了 Wait()。
  • 如果你在 pid:1 的 docker 容器中运行进程(即使你最终调用了wait),它也会导致僵尸。 github.com/krallin/tini 在这种情况下会有所帮助。
  • @Anfernee 我不太确定 Chris 在说什么,但忽略 SIGCHLD 意味着你没有收到信号,并不是说子进程不会变成僵尸,因为你已经发现。
【解决方案2】:

同意第一个答案,即退出进程成为僵尸,直到该进程被另一个进程等待。以下是我在 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)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-10-16
    • 2010-11-12
    • 2014-05-09
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多