在孩子进程死后等待孙子

时间:2013-11-19 16:32:20

标签: c unix process fork wait

我使用以下代码等待所有子进程完成:

int pid;
do {
    pid = wait(NULL);
} while (pid != -1);

然而,如果我的孙子孙女在他们的父进程死亡的情况下运行,它似乎不起作用。例如,假设我有一个处理孩子Beta的过程Alpha,并且Beta分叉一个孩子Gamma。然后Beta在Gamma继续运行时死亡。我希望能够让Alpha等待Gamma完成。问题在于我无法存储Gamma的进程ID - Alpha需要能够等待所有的孩子,孙子,曾孙等完成而不知道他们的个人pid。可以这样做(如果是这样的话)?

3 个答案:

答案 0 :(得分:3)

这不容易做到。

当一个进程退出时,它的子进程被重新分配给进程1(init),因为这是wait()在任何子进程上唯一可以预期的进程,即使是它不知道的进程 - 其他进程可能不知道如何处理SIGCHLD,甚至忽略它们没有启动的进程,从而创建了僵尸进程。

没有办法宣称你的过程想要清理任何孙子孙女,而且总是期待清理孩子。

要做的就是让 Beta 进入“等待孩子”状态而不是终止,或者从 Alpha 启动所有子进程。< / p>

答案 1 :(得分:3)

在原始进程中创建pipe,并让所有后代继承管道的写入端。终止后代将隐式关闭其继承的文件描述符。当写入端的最后一个文件描述符关闭时,管道的读取端将立即可读为EOF。

因此,当原始进程准备好等待所有后代的终止时,它会关闭其写入端,然后等待读取端的EOF:

#ifdef FOR_REAL
# include <error-checking.h>
#endif

int p[2];

pipe(p);              // Parent

if (! fork()) {       // Child
  close(p[0]);        // Child:  close inherited p[0] (not needed)
  ...
  if (! fork()) {     // Grandchild
    ...
    exit(0);          // Grandchild:  inherited p[1] implicitly closed
  }
  ...
  exit(0);            // Child:  inherited p[1] implicitly closed
}

...

// Wait for all descendants to finish
char buf[1];

close(p[1]);
read(p[0], &buf, 1);  // Returns 0 (EOF).  Could also select(2) or poll(2)

答案 2 :(得分:3)

实际上有一种方法可以优雅地等待孙子孙女。从Linux 3.4开始,有一个名为PR_SET_CHILD_SUBREAPER的新API,它可以使父进程变成init。父进程将重新显示其后代中的所有孤儿。

从PRCTL(2)的手册页复制以下内容:

  

subreaper为其后代履行init(1)的角色                 流程。当一个过程变成孤儿时(即它的过程)                 直接父母终止)然后该过程将是                 归属于最近的仍然生活的祖先subreaper。                 随后,在孤立进程中调用getppid()将会                 现在返回subreaper进程的PID,并且当                 孤儿终止,它将是subreaper进程                 接收SIGCHLD信号,并且能够等待(2)                 发现终止状态的过程。