例如,在父进程中,我分叉子进程并等待子进程:
int main() {
setSignal(SIGCHLD, sigchld_handler)
while(1) {
// fork some child processes
myForkFunction()
waitpid(-1, &status, 0)
}
}
此外,我有一个SIGCHLD信号处理程序:
void
sigchld_handler(int sig) {
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
// Reap zombie processes
}
}
可以看出,waitpid()
函数和main()
函数中都显示sigchld_handler()
。我想知道waitpid
是否可以打断SIGCHLD
。如果它可以被SIGCHLD
打断,那么接下来会发生什么?
有没有人对此有任何想法?
答案 0 :(得分:2)
waitpid()
的POSIX规范部分说明:
如果定义了_POSIX_REALTIME_SIGNALS,并且实现对SIGCHLD信号进行排队,那么如果
wait()
或waitpid()
返回,因为子进程的状态可用,则任何与进程ID相关联的待处理SIGCHLD信号子进程应该被丢弃。任何其他待处理的SIGCHLD信号应保持待定状态。否则,如果SIGCHLD被阻止,如果由于子进程的状态可用而返回
wait()
或waitpid()
,则除非另一个子进程的状态可用,否则应清除任何未决的SIGCHLD信号。对于所有其他条件,未指明在传递SIGCHLD信号时是否可以使用子状态。
引用段落中的第三段似乎意味着你正在踩着薄冰。它没有提到“实现定义”或类似的 - 未指明意味着标准没有说明将发生什么,您可能会或可能不会从特定于实现的文档中获取任何信息。
POSIX规范中有很多(措辞非常密集)信息。还有一些例子和理由 - 提到sigwait()
和sigwaitinfo()
。值得阅读整个waipid()
页面。您也应该阅读Signal concepts - 阅读更密集。 (其中一天,我也会这样做 - 当我需要了解以前没有涉及过的信号时。)
为什么使用WUNTRACED
代替0
或WNOHANG
? WUNTRACED
是一个非常专业的条件 - POSIX说:
WUNTRACED
pid指定的任何已停止的子进程的状态,以及自停止后尚未报告的状态,也应报告给请求进程。
类似的评论适用于WCONTINUED
。当你需要它们时,这两个标志很有用,但你很少需要它们。
我建议您通常在0
的第三个参数中使用WNOHANG
或waitpid()
。
答案 1 :(得分:1)
是的,从某种意义上说,只有其中一个能够成功完成特定的子进程;如果信号处理程序中断了main
中的那个,那么在信号处理程序返回之后,孩子就已经被收获了,main
中的调用将会失败。
然而,据说,编写这样的代码是不好的做法。应该有一个地方处理给定子进程的收获,通常信号处理程序是一个非常糟糕的选择,因为它是全局的,它必须知道你的程序可能已经完成的所有可能的子进程,和有办法将这些结果传达给程序的适当部分。
相反,通常最好通过管道进出子进程的poll
来监视子进程的终止,并且只有waitpid
知道它被终止后才会被终止,或者执行阻塞{{} 1}}来自一个唯一的工作是等待孩子的线程。