waitpid()是Linux中的原子操作吗?

时间:2016-07-04 00:52:48

标签: c linux unix signals system-calls

例如,在父进程中,我分叉子进程并等待子进程:

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打断,那么接下来会发生什么?

有没有人对此有任何想法?

2 个答案:

答案 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代替0WNOHANGWUNTRACED是一个非常专业的条件 - POSIX说:

  

WUNTRACED
    pid指定的任何已停止的子进程的状态,以及自停止后尚未报告的状态,也应报告给请求进程。

类似的评论适用于WCONTINUED。当你需要它们时,这两个标志很有用,但你很少需要它们。

我建议您通常在0的第三个参数中使用WNOHANGwaitpid()

答案 1 :(得分:1)

是的,从某种意义上说,只有其中一个能够成功完成特定的子进程;如果信号处理程序中断了main中的那个,那么在信号处理程序返回之后,孩子就已经被收获了,main中的调用将会失败。

然而,据说,编写这样的代码是不好的做法。应该有一个地方处理给定子进程的收获,通常信号处理程序是一个非常糟糕的选择,因为它是全局的,它必须知道你的程序可能已经完成的所有可能的子进程,和有办法将这些结果传达给程序的适当部分

相反,通常最好通过管道进出子进程的poll来监视子进程的终止,并且只有waitpid知道它被终止后才会被终止,或者执行阻塞{{} 1}}来自一个唯一的工作是等待孩子的线程。