1

我正在尝试制作一个 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 将被另一个覆盖。

我怎样才能避免这种情况?

4

1 回答 1

2

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

一种可靠的方法是将SIGCHLD信号转换为文件描述符事件,然后将其集成到事件循环中(select, poll, epoll...)。当你观察一个事件时,你waitpid(..., WNOHANG)在一个循环中使用来收集所有死去的孩子。在此处查看我的答案的更多信息:https ://stackoverflow.com/a/8398491/1020667

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

另一方面,您可以通过使用可移植的事件循环库来绕过所有这些低级细节。一些库已经提供了启动和监视子进程的设施。我推荐libuv(node.js)。

于 2014-11-09T11:18:01.060 回答