如何获取死子进程的PID并在父进程中使用它?

时间:2014-11-09 10:32:34

标签: 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 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会被另一个孩子覆盖。

我该如何避免这种情况?

1 个答案:

答案 0 :(得分:2)

您不应该从信号处理程序执行此操作。你不应该从信号处理程序做任何事情(如果你想保持理智)。

一种可靠的方法是将SIGCHLD信号转换为文件描述符事件,并将其集成到事件循环中(selectpollepoll ...)。观察事件时,在循环中使用waitpid(..., WNOHANG)来收集所有死去的孩子。请在此处详细了解我的回答:https://stackoverflow.com/a/8398491/1020667

上述答案假设您使用Linux并使用signalfd(特定于Linux的工具)将信号转换为文件描述符。但也可以使用" self-pipe"技巧(非常小心),或kqueue(FreeBSD,OSX)。请注意,对于kqueue,没有中间文件描述符,您可以像文件描述符事件一样直接接收信号事件。

另一方面,您可以使用便携式事件循环库来解决所有这些低级细节。一些图书馆已经提供了启动和观看子进程的工具。我推荐libuv(node.js)。