当 parent 和 child 执行 exec() 时等待 child

wait for a child when both parent and child do an exec()

我发现了这个有趣的问题(注意我刚开始研究这个,所以我是 UNIX 系统调用、信号等方面的新手)目前我无法解决:

假设我们在 main.c 上有以下代码:

switch (fork()) {
    case -1:
        printf("error!");
        break;
    case 0: // child process
        execvp(childCommands[0], childCommands);
        break;
    default: // parent process
        execvp(parentCommands[0], parentCommands);
        break;
}

原始 parent 进程是否有可能在其 child 上执行 wait()?

据我所知,挂起信号在执行 exec() 后仍保持挂起状态,但为它们定义的任何捕获函数都不会挂起,所以我不确定是否可以在这里完成任何“信号魔术”。

作为parent进程的原程序运行被switchdefault子句执行的新程序所取代,并且(假设execvp() 成功),这意味着原始程序无法等待其 child — 原始程序不再是 运行.

但是,替换程序有一个可以等待的 child,但是替换程序不太可能知道 child 的存在,直到它发现它得到了 child child 的状态,它在调用 wait() 函数族之一时从未创建过。这意味着任何分叉其他进程并随后等待死亡 children 的程序都应该容忍来自它没有创建的进程的尸体;它的前身程序可能创建了刚刚死亡的进程。

您可能需要更改进程树的组织。例如,原始进程可以 fork 两次,第二个 child 将执行由 parentCommands 数组标识的命令,而原始进程等待两个 children 死亡。

或者,也许原始程序可以告诉替换程序 child 以某种方式存在。有很多方法可以做到这一点(参数、环境变量、IPC 机制等)。

不,没有魔法。由 parent 执行的程序当然可以收获 children,如果它被设计为这样做的话。但如果不是,就会让他们堆积成丧尸。您可以将 SIGCHLD 设置为 SIG_IGN 之前,这应该可以防止 children 变成僵尸,但这并不能保证在 execve() (1).

中存活下来

每个人在 window 经理中所做的事情就是“double-fork”——在 child 中再次分叉并在 grand-child 中执行 execve ,child 立即退出,等待并被其 parent 收割,并放弃 grand-child 的命运(由 init 或“subreaper”采用)。

(1) 它会在 Linux 但不会在 OpenBSD 上。但即使这样做,执行的程序也可能有其他想法:例如设置自己的 SIGCHLD 处理程序并被意想不到的 children.

弄得非常困惑