2016-03-17 148 views
7

我在Go中有一個應用程序,用於重新路由二進制文件的STDIN和STDOUT,然後運行它們。概括地說,我做的:Golang:子進程成爲殭屍

- 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退出的過程中,它成爲在進程表殭屍進程。

下面是一個例子:

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。

回答

11

當一個進程退出時,它總是成爲一個殭屍,無論其他進程在運行。這只是過程終止的方式。該過程將保持殭屍狀態,直到父母呼叫wait以獲得其退出狀態,或者通過忽略SIGCHLD(可能在孩子退出之前)表示它對孩子不感興趣。在這種情況發生之前它仍然是殭屍,以免退出狀態丟失。

在你的例子中,你的進程(創建進程的進程)似乎是父進程,所以在你的進程收集它們之前,A和B都將保持殭屍狀態。

如果一個進程在它仍然有孩子(跑步或殭屍)時退出,這些孩子將被重新設置到退出進程的父級,這通常會忽略退出狀態(清理殭屍)。

+0

那麼,SIGCHLD是由子進程發送之前,他們成爲殭屍?那麼如何「忽略」SIGCHLD?通過捕捉信號而無所作爲? – AJPennster

+0

當兒童作爲殭屍的一部分時,內核發送SIGCHLD。如果你想忽略SIGCHLD並且仍然獲得殭屍,那麼將SIGCHLD動作設置爲SIG_DFL(默認值)而不是SIG_IGN--默認動作是什麼都不做,但仍然會獲得殭屍。 –

+0

我不想殭屍,我想要清理退出的進程。我試圖在主應用程序中設置信號來忽略SIGCHLD,並且仍然製作殭屍,所以我最終調用了Wait()。 – AJPennster

2

同意退出進程變成殭屍的第一個答案,直到該進程被另一進程等待。以下是我如何處理事情。

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) 
}