繁体   English   中英

子进程错过了信号

[英]Signal missed by child process

为了初始化应用程序,父进程会派生3个子进程,然后子进程设置其信号处理程序,并向父进程发信号通知它们已准备好开始活动。 SIGUSR1信号用于实现此目的。

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

事实证明,所有信号都是由父母为每个孩子发送的; 但是,大多数情况下,子进程之一会丢失信号。 在多次试验中,我确定了父级首先向其发送信号的过程会错过它。 但是,有时也会发生所有子进程错过其信号的情况。 我还使用了“ strace”工具来检查所有信号的流向,但似乎仍然无法确定为什么子进程无法捕获父进程发送的信号。

任何反馈将不胜感激。

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

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

POSIX实时信号已排队(上限),因此您丢失信号的可能性较小。

但是,我不会使用信号来跟踪子进程。 我将使用管道,其中子级具有写端,父级具有读端,并且所有描述符都使用fcntl(descriptor, O_SETFD, O_CLOEXEC)标记为执行时关闭。

子代通过一字节消息更新父代的状态。 如果子级退出或执行另一个程序,则父级将其视为文件结束条件( 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)来使描述符在执行时关闭,就像在管道情况下一样。

用Unix域套接字对(任何类型的-问题SOCK_STREAMSOCK_DGRAMSOCK_SEQPACKET ),是它们可以包含辅助数据 辅助数据可以包含其他文件描述符,它们是有限的商品。 如果存在不可信或令人讨厌的子进程,它可能会通过向其发送数千个文件描述符来杀死其父进程。 为了安全起见,父进程应该监视从子进程接收的内容,如果它包含辅助数据,请立即关闭该描述符(因为子进程显然是敌对的!),如果提供了任何文件描述符,也请关闭它们。 如果您对子进程的信任程度与对原始进程的信任程度一样高,则可以避免这种情况。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM