5

问题

SIGPIPE是否可以在写入pipe()FD时禁用信号 ( ) 的提升,而无需安装我自己的信号处理程序或全局禁用/屏蔽信号?


背景

我正在研究一个偶尔创建管道的小型库,以及fork()一个等待来自父级消息的临时子/虚拟进程。当子进程收到来自父进程的消息时,它会(故意)死亡。


问题

子进程在我无法控制的情况下运行来自另一个(第三方)库的代码,该库很容易崩溃,所以我不能总是确定子进程在我write()进入管道之前是活跃的。

这导致我有时会尝试write()在子进程结束时已经死/关闭的管道,并且它会SIGPIPE在父进程中引发 a。我在其他客户将使用的库中,因此我的库必须尽可能独立且对调用应用程序透明。安装自定义信号处理程序可能会破坏客户的代码。


工作至今

我已经通过使用解决了套接字的这个问题setsockopt(..., MSG_NOSIGNAL),但是我找不到任何与管道等效的功能。我已经考虑过临时安装一个信号处理程序来捕获SIGPIPE,但我没有看到任何方法可以将其范围限制在我的库中的调用函数而不是整个过程(而且它不是原子的)。

我在 SO 上也发现了一个类似的问题,它问的是同样的问题,但不幸的是,使用poll()/select()不会是原子的,并且子进程在我的select()write()调用之间死亡的可能性很小(但可能)。


问题(redux)

有没有办法完成我在这里尝试的事情,或者在不触发将生成的行为的情况下原子地检查并写入管道SIGPIPE?此外,是否有可能实现这一点知道子进程是否崩溃?知道它是否崩溃可以让我为提供“崩溃”库的供应商构建一个案例,并让他们知道它失败的频率。

4

3 回答 3

1

SIGPIPE写入pipe()FD [...]时是否可以禁用信号 ( ) 的提升?

父进程可以保持其管道读取端的副本打开。那么总会有一个读者,即使它并没有真正阅读,所以SIGPIPE永远不会满足 a 的条件。

问题在于这是一个死锁风险。如果孩子死了,然后父母执行了一个无法容纳在管道缓冲区中的阻塞写入,那么你就完蛋了。不会从管道中读取任何内容来释放任何空间,因此写入永远不会完成。避免这个问题是我们的SIGPIPE首要目的之一。

waitpid()您还可以通过with 选项在尝试写作之前测试孩子是否还活着WNOHANG。但这引入了一种竞争条件,因为孩子可能会在waitpid()写入之间死亡。

但是,如果您的写入始终很小,并且如果您从孩子那里获得足够的反馈以确信管道缓冲区没有备份,那么您可以将这两者结合起来形成一个合理可行的系统。

于 2016-12-16T18:35:58.950 回答
1

在尝试了所有可能的方法来解决这个问题之后,我发现只有两个地方可以解决这个问题:

  • 使用socketpair(PF_LOCAL, SOCK_STREAM, 0, fd), 代替管道。
  • 创建一个“牺牲”子进程,如果被引发fork()则允许崩溃。SIGPIPE

我走的socketpair路线。我不想这样做,因为它涉及重新编写相当多的管道逻辑,但这并不太痛苦。

谢谢!

于 2016-12-19T03:46:43.760 回答
0

不确定我是否遵循:是父进程,即写入管道。您这样做是为了在一段时间后发送一条消息。子进程以某种方式解释消息,完成它必须做的事情并退出。您还必须等待它,您不能先准备好消息,然后再生成一个孩子来处理它。同样,仅仅发送一个信号并不能解决问题,因为孩子必须真正根据消息的内容采取行动,而不仅仅是“做”电话。

想到的第一个技巧是您不会关闭父级管道的读取端。这使您可以自由地写入管道,同时不会损害孩子的阅读能力。

如果这不好,请详细说明问题。

于 2016-12-16T19:00:55.750 回答