繁体   English   中英

Boost.asio和UNIX信号处理

[英]Boost.asio & UNIX signal handling

前言

我有一个通过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内部互斥io_service死锁。 我想到的唯一事情就是使用一些管道或socketpair在那里写通知,在另一端使用async_wait ,因为它有时会处理poll()事件循环中的信号。

还有更好的解决方案吗?

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

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

我尝试了很多不同的解决方案,包括一些需要检测正在使用哪种类型的线程的解决方案。 最终帮助我解决这个问题的是标题为信号处理程序中断系统调用和库函数的部分(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。 然后,您可以为线程类型选择最佳解决方案。

如果您已经在轮询IO,另一个非常简单的解决方案就是使用布尔值来表示其他线程。 布尔值总是为零或不是因此不存在部分更新和竞争条件的可能性。 然后,您可以设置此布尔标志,而不使用其他线程读取的任何互斥锁。 像valgrind这样的工具不会喜欢它,但在实践中它可以工作。

如果你想更加正确,你可以使用gcc的原子,但这是编译器特定的。

暂无
暂无

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

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