【问题标题】:Signal missed by child process子进程错过了信号
【发布时间】:2016-01-21 08:21:25
【问题描述】:

为了初始化应用程序,父进程派生出 3 个子进程,然后子进程设置它们的信号处理程序并向父进程发出信号,表明它们已准备好开始活动。 SIGUSR1 信号用于实现这一点。

与此同时,父进程正在等待来自子进程的这些信号。收到信号后,父进程将其 pid 与其存储的子 pid 匹配,并增加一个计数器。一旦父进程知道已收到来自所有子进程的继续信号,它就会开始向每个子进程发送一个 SIGUSR1 信号以指示开始活动。

验证了所有信号都是从父级为每个子级发送的这一事实;但是,大多数情况下,其中一个子进程会错过信号。经过多次试验,我发现父母首先向其发送信号的过程错过了它。然而,有时也会发生所有子进程都错过其信号的情况。我还使用 'strace' 工具检查了所有信号的流向,但似乎仍然无法确定子进程无法捕获父进程发送的信号的原因。

我们将不胜感激。

【问题讨论】:

  • 文字描述代码非常模糊,请尝试创建Minimal, Complete, and Verifiable Example 并显示给我们,如果有输出,请同时提供实际和预期的输出。
  • 正如 Joachim 所说,有很多事情可能会出错,如果没有 MCVE,我们就不可能为您提供帮助。你怎么知道哪个孩子发出了每个信号?你怎么知道父母已经成功地给每个孩子发送了信号?没有看到代码,我们无法开始猜测这些问题的答案。
  • 它本质上是不可靠的 :)

标签: c linux process signals


【解决方案1】:

SIGUSR1 和其他 POSIX 信号没有排队。如果该进程已经有一个待处理,则任何其他信号都将被丢弃。

您可以通过使用“实时信号”来避免这种情况。您可以像使用标准 POSIX 信号一样使用它们;第一个名为SIGRTMIN+0,最后一个名为SIGRTMAX-0。如果您使用sigqueue(),您甚至可以附加一个int(或空指针)作为有效负载。

POSIX 实时信号已排队(有上限),因此您不太可能丢失它们。

但是,我不会使用信号来跟踪子进程。我会使用管道,子节点具有写入端,父节点具有读取端,所有描述符都使用fcntl(descriptor, O_SETFD, O_CLOEXEC) 标记为close-on-exec。

孩子通过单字节消息更新父母的状态。如果子进程退出或执行另一个程序,父进程会将其视为文件结束条件(read() 返回零)。如果父级退出,子级写入端的写入端将变为不可写入,并且任何写入管道的尝试都将失败并出现EPIPE 错误。 (它还会引发SIGPIPE 信号,因此您可能希望使用sigaction() 来忽略SIGPIPE 信号。)

父进程可以使用select()poll() 并行监控子进程状态。每当子进程发送数据,或退出或执行另一个程序(关闭管道的写端)时,父描述符(管道的读端)将变得可读。就个人而言,我还使用fcntl(rfd, F_SETFL, O_NONBLOCK) 将父描述符标记为非阻塞,这样如果出现故障,而不是阻塞误读,对父描述符的读取将失败,并在 errno 中显示EWOULDBLOCK

如果您想要双向数据流,最简单的方法是为每个孩子使用一个额外的管道,父写入和子读取。

也可以使用未命名的 Unix 域数据报套接字(通过 socketpair(AF_UNIX, SOCK_DGRAM, 0, fds) 创建。(有关参数的详细信息,请参见 man 2 socketman 7 unix。)也可以使用 fcntl(fds[0], F_SETFL, O_CLOEXEC)fcntl(fds[1], F_SETFL, O_CLOEXEC)描述符 close-on-exec,就像在管道的情况下一样。

Unix 域套接字对(任何类型——SOCK_STREAMSOCK_DGRAMSOCK_SEQPACKET)的问题在于它们可以包含辅助数据。这个辅助数据可以包含额外的文件描述符,这是一种有限的商品。如果存在不可信或讨厌的子进程的可能性,它可能会通过向其发送几千个文件描述符来杀死其父进程。为了安全起见,父进程应该监视它从子进程接收到的内容,如果它包含辅助数据,则立即关闭该描述符(因为子进程显然是敌对的!),如果提供了任何文件描述符,也将其关闭。只有当你信任你的子进程就像你信任你的原始进程没有做任何邪恶的事情一样,你才能避免这种情况。

确保 unix 域套接字的安全并不难,但检查每个接收到的数据报或接收辅助数据是几十行额外的代码。管道更简单。

【讨论】:

    猜你喜欢
    • 2015-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 2016-05-20
    相关资源
    最近更新 更多