Boost.asio和UNIX信号处理

Pau*_*hov 15 c++ linux multithreading signals boost-asio

前言

我有一个通过Boost.Asio运行的多线程应用程序.boost::asio::io_service整个应用程序只有一个,所有的东西都是由一组线程完成的.有时需要使用fork和exec生成子进程.当孩子终止时,我需要在上面做waitpid以检查退出代码和收集僵尸.我最近添加boost::asio::signal_set但是在使用linux-2.4.*内核的古老系统中遇到了问题(不幸的是仍然被一些客户使用).在较旧的Linux内核下,线程实际上是一个特殊的进程情况,因此如果一个子程由一个线程生成,另一个线程无法使用waitpid系统调用系列等待它.Asio的signal_set将信号处理程序发布到,io_service并且运行此服务的任何线程都可以运行此处理程序,这不适合我的情况.所以我决定以旧的良好信号/ sigaction方式处理信号 - 所有线程都有相同的处理程序来调用waitpid.所以还有另一个问题:

问题

当处理程序捕获信号并且进程成功进行sigwaited时,如何io_service从处理程序"发布"给我?在我看来,显而易见的io_service::post()方法是不可能的,因为io_service如果信号在错误的时间发生,它可能会在内部互斥锁上死锁.我想到的唯一一件事就是使用一些管道或socketpair来async_wait在那里写通知,而另一端则是为了处理poll()事件循环中的信号.

还有更好的解决方案吗?

jco*_*and 2

我没有处理过 boost::asio 但我已经解决了类似的问题。我相信我的解决方案适用于 LinuxThreads 和较新的 NPTL 线程。

我假设您想要“发布”信号到 *io_service* 的原因是中断系统调用,以便线程/程序将干净地退出。它是否正确?如果没有,也许您可​​以更好地描述您的最终目标。

我尝试了很多不同的解决方案,包括一些需要检测正在使用哪种类型的线程的解决方案。最终帮助我解决这个问题的是man signal(7) 的信号处理程序中断系统调用和库函数的部分。

关键是在信号处理线程中使用sigaction()而不使用SA_RESTART,为要捕获的所有信号创建处理程序,在信号处理线程中使用pthread_sigmask(SIG_UNBLOCK, sig_set, 0)取消屏蔽这些信号并屏蔽相同的信号在所有其他线程中设置信号。处理程序无需执行任何操作。只要有一个处理程序就可以改变行为,并且不设置SA_RESTART就可以允许可中断的系统调用(如write ())中断。然而,如果您使用sigwait(),其他线程中的系统调用不会被中断。

为了轻松屏蔽所有其他线程中的信号。我启动信号处理线程。然后在启动任何其他线程之前屏蔽主线程中想要处理的所有信号。然后,当其他线程启动时,它们会复制主线程的信号掩码。

关键是,如果您这样做,那么您可能不需要向 *io_service* 发送信号,因为您只需检查系统调用中的中断返回代码即可。我不知道这如何与 boost::asio 一起使用。

因此,这一切的最终结果是,我可以捕获我想要的信号,例如 SIGINT、SIGTERM、SIGHUO 和 SIGQUIT,以便执行干净关闭,但我的其他线程仍然会中断其系统调用,并且也可以干净退出而无需任何通信在信号线程和系统的其余部分之间,无需在信号处理程序中执行任何危险操作,并且单个实现可以在 LinuxThreads 和 NPTL 上工作。

也许这不是您正在寻找的答案,但我希望它有所帮助。

注意:如果您想确定系统是否正在运行 LinuxThreads,您可以通过生成一个线程,然后将其 PID 与主线程的 PID 进行比较来实现。如果它们不同,那就是 LinuxThreads。然后您可以选择适合螺纹类型的最佳解决方案。