当 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进程的原程序运行被switch
的default
子句执行的新程序所取代,并且(假设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.
弄得非常困惑
我发现了这个有趣的问题(注意我刚开始研究这个,所以我是 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进程的原程序运行被switch
的default
子句执行的新程序所取代,并且(假设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.