C 如何获取死子进程的PID并在父进程中使用它?
我正在尝试制作一个C程序(用于FreeBSD,Unix),它在一个循环中创建4个子进程。每个孩子都会做一些事情,当他们死后,他们会立即被其他孩子取代。最后,我有4个孩子一直在工作 每个子PID必须在表中注册,并且在它们失效后,必须删除表的PID。这是我遇到麻烦的部分 因此,在第一次尝试中,我尝试创建一个处理程序,该处理程序向全局变量发送死孩子的PID:C 如何获取死子进程的PID并在父进程中使用它?,c,unix,fork,freebsd,sigchld,C,Unix,Fork,Freebsd,Sigchld,我正在尝试制作一个C程序(用于FreeBSD,Unix),它在一个循环中创建4个子进程。每个孩子都会做一些事情,当他们死后,他们会立即被其他孩子取代。最后,我有4个孩子一直在工作 每个子PID必须在表中注册,并且在它们失效后,必须删除表的PID。这是我遇到麻烦的部分 因此,在第一次尝试中,我尝试创建一个处理程序,该处理程序向全局变量发送死孩子的PID: int global_variable; void handler_SIGCHLD(int sig) { pid_t son;
int global_variable;
void handler_SIGCHLD(int sig)
{
pid_t son;
int e;
do {
son = wait3(&e, WNOHANG, NULL);
if ((son > (pid_t)0) && (WIFEXITED(e) || WIFSIGNALED(e)))
{
global_variable = son;
}
} while (son > (pid_t)0);
}
然后我在父级中使用它从表中删除死亡子级的PID。但后来我意识到,如果两个孩子同时死亡,其中一个PID将被另一个PID覆盖
我怎样才能避免这种情况 您不应该从信号处理程序执行此操作。你不应该在信号处理器上做任何事情(如果你想保持理智的话) 一种可靠的方法是将
SIGCHLD
信号转换为文件描述符事件,并将其集成到事件循环中(select
,poll
,epoll
…)。观察事件时,在循环中使用waitpid(…,WNOHANG)
来收集所有死亡的孩子。有关我的答案,请参见此处:
上面的答案假设您在Linux上,并使用signalfd
(Linux专用工具)将信号转换为文件描述符。但是,您也可以使用“自我管道”技巧(非常小心),或kqueue
(FreeBSD、OSX)。请注意,对于kqueue
,没有中间文件描述符,您直接接收信号事件,就像文件描述符事件一样
另一方面,通过使用可移植的事件循环库,您可以绕过所有这些低级细节。一些库已经提供了启动和监视子进程的工具。我推荐
libuv
(node.js)。对不起,我忘了说我使用的是FreeBSD(Unix)。@Vertice然后你可以使用kqueue,请参阅更新的答案。请等待在任何处理程序之外没有WNOHANG的孩子。在SIGHCLD处理程序中不执行任何操作。或者,如果必须在处理程序中执行此操作,请不要使用单个全局变量,而是使用一个死PID数组,这样它们就不会相互覆盖。另一种选择是。在处理程序中,设置一个sig_atomic_t
标志并返回。在处理程序外部,如果设置了标志,则按住SIGCHLD,执行while(son=wait3(&e,WNOHANG,NULL)){…}
操作,然后重新启用SIGCHLD。