为什么子进程“sleep 10”不会终止?

chm*_*ike -2 unix go

我需要测试一个进程是否终止,我所拥有的只是它的 pid 号。为此,我测试伪文件“/proc/<pid>”是否存在。

为这个函数编写一个测试,我注意到这个过程没有按预期终止。

对于测试,我将“sleep 10”作为子进程运行,它应该运行 10 秒。开始这个过程后,我轮询伪文件“/proc/<pid>”是否消失。该伪文件永远不会消失,也不会检测到子进程的终止。

测试golang playground的代码,重现问题:https : //play.golang.org/p/fb4CbXkIjh3

我检查了该进程是否已创建,并且 pid 是否正确。在检查过程中看到它变成了<defunct>。它没有因此被删除。

问题如下:

  1. 为什么子进程不终止?
  2. 如何更改代码以使其终止?
package main

import (
    "fmt"
    "log"
    "os"
    "os/exec"
    "strconv"
    "time"
)

func main() {
    fmt.Println("Hello, playground")

    cmd := exec.Command("sleep", "10")
    if err := cmd.Start(); err != nil {
        log.Fatal("unexpected error:", err)
    }
    pidStr := strconv.Itoa(cmd.Process.Pid)
    log.Println("sleep pid:", pidStr)

    for {
        if _, err := os.Stat("/proc/" + pidStr); os.IsNotExist(err) {
            log.Println("detect termination of /proc/" + pidStr)
            return
        }
        log.Println("pgm /proc/" + pidStr + " is running")
        time.Sleep(3 * time.Second)
    }
}
Run Code Online (Sandbox Code Playgroud)

tor*_*rek 5

在操作系统层面,在任何兼容 POSIX 的操作系统(Unix、Linux、Darwin 等)中,已完成但尚未被其上级收集的进程处于“defunct”或“zombie”状态。它仍然存在,但不能被杀死:它已经死了。它的存在正是为了让它的上级——可以调用操作系统级wait系统调用的进程——可以调用操作系统级wait系统调用并看到进程现在已经死了。

一旦它的上级等待它,该进程就被真正删除了:不再有僵尸进程占用该进程 ID。如果你有一个/proc文件系统,这是进程从/proc.

在 Go 中,调用会cmd.Wait()调用操作系统级别的wait调用,因此这就是执行此操作的方法。如果您想收集 this 的结果cmd.Wait(),一个好的方法是通过一个通道发送它。

(如果你想生成一个很长的运行进程而不是等待它,你可以拒绝它,这样你就不再是它的优越者。正确执行此操作的细节充满了特定于操作系统的小玩意,例如丢弃控制 tty 、设置会话、使用procctlprctl等。)