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

Is waitpid() an atomic operation in Linux?

比如在父进程中,我fork了一个子进程,等待子进程:

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打断,那又会怎样呢?

有人对此有什么想法吗?

是的,从某种意义上说,对于给定的 child 过程,只有其中一个可以成功;如果信号处理程序中断了 main 中的信号处理程序,那么在信号处理程序 returns 之后,child 将已经被回收并且 main 中的调用将失败。

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

相反,通常最好通过 poll 在管道 to/from 和 child 进程上监视 child 进程的终止,并且仅 waitpid在你知道它终止之后,或者从一个线程执行阻塞 waitpid,该线程唯一的工作就是等待 child.

waitpid() 的 POSIX 规范部分说:

If _POSIX_REALTIME_SIGNALS is defined, and the implementation queues the SIGCHLD signal, then if wait() or waitpid() returns because the status of a child process is available, any pending SIGCHLD signal associated with the process ID of the child process shall be discarded. Any other pending SIGCHLD signals shall remain pending.

Otherwise, if SIGCHLD is blocked, if wait() or waitpid() return because the status of a child process is available, any pending SIGCHLD signal shall be cleared unless the status of another child process is available.

For all other conditions, it is unspecified whether child status will be available when a SIGCHLD signal is delivered.

引用的第三段似乎暗示您如履薄冰。它没有提到 'implementation defined' 或类似的东西——未指定意味着标准没有说明会发生什么,你可能会也可能不会从特定于实现的文档中获得任何信息。

POSIX规范中有很多(措辞非常密集)的信息。还有一些例子和一个基本原理——也提到了 sigwait() and sigwaitinfo(). It is worth reading the whole of the waipid() page. You should probably also read about Signal concepts——更密集的阅读。 (有一天,我也会这样做——当我需要了解一些我以前没有涉及过的信号时。)


您为什么使用 WUNTRACED 而不是 0WNOHANGWUNTRACED 是一个非常特殊的条件 — POSIX 说:

WUNTRACED
The status of any child processes specified by pid that are stopped, and whose status has not yet been reported since they stopped, shall also be reported to the requesting process.

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

我建议您通常应该在 waitpid() 的第三个参数中使用 0WNOHANG