我正在尝试编写一个 C 程序(适用于 FreeBSD、Unix),它在循环中创建 4 个子进程。每个 child 都会做事,当他们死后,他们会立即被其他 child 取代。所以,最后我有4个 child 一直在工作。
每个子 PID 都必须注册在一个表中,当它们死亡后,表中的 PID 必须被删除。这是我遇到麻烦的部分。
因此,在第一次尝试中,我尝试创建一个处理程序,将死亡 child 的 PID 发送到全局变量:
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。但后来我意识到,如果两个 child 同时死亡,其中一个 PID 将被另一个覆盖。
如何避免这种情况?
最佳答案
您不应该从信号处理程序中执行此操作。您不应该从信号处理程序中执行任何操作(如果您希望保持理智)。
可靠的方法是将 SIGCHLD
信号转换为文件描述符事件,然后将其集成到事件循环中(select
、poll
、epoll
...)。当您观察一个事件时,您可以在循环中使用 waitpid(..., WNOHANG)
来收集所有死去的 child 。在这里查看我的答案的更多信息:https://stackoverflow.com/a/8398491/1020667
以上答案假设您使用的是 Linux 并使用 signalfd
(Linux 特定工具)将信号转换为文件描述符。但是,您也可以使用“自管道”技巧(非常小心)或kqueue
(FreeBSD、OSX)。请注意,使用kqueue
,没有中间文件描述符,您可以像文件描述符事件一样直接接收信号事件。
另一方面,您可以通过使用可移植事件循环库来解决所有这些低级细节。一些库已经提供了启动和监视子进程的工具。我推荐(node.js 的)libuv。
关于c - 如何获取已死亡子进程的 PID 并在父进程中使用它?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26827230/