前言

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

问题

当信号被处理程序捕获并且成功完成信号处理时,如何将其从处理程序“发布”到我的io_service中?在我看来,明显的io_service::post()方法是不可能的,因为如果信号在错误的时间到来,它可能会在io_service内部互斥锁上死锁。我唯一想到的是使用一些管道或套接字对在那儿写通知,并在另一端写async_wait,因为有时这样做是为了处理poll()事件循环中的信号。

有更好的解决方案吗?

最佳答案

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

我假设您要向io_service *发送信号的原因是中断系统调用,因此线程/程序将干净地退出。这样对吗?如果不是,也许您可​​以更好地描述您的最终目标。

我尝试了许多不同的解决方案,包括一些需要检测使用哪种类型的线程的解决方案。最终帮助我解决此问题的是标题为man signal(7)的Signal Handlers中断系统调用和库函数的部分。

关键是在信号处理线程中不使用 SA_RESTART 来使用 sigaction()来创建要捕获的所有信号的处理程序,使用 pthread_sigmask(SIG_UNBLOCK,sig_set,0)来取消屏蔽这些信号处理线程并屏蔽所有其他线程中设置的相同信号。处理程序无需执行任何操作。仅具有处理程序即可更改行为,而不设置 SA_RESTART 即可中断可中断的系统调用(例如编写())。而如果您使用 sigwait(),则其他线程中的系统调用不会中断。

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

关键是,如果执行此操作,则可能不需要将信号发布到* io_service *,因为您可以仅检查系统调用中的中断返回码。我不知道这如何与boost::asio一起工作。

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

也许这不是您想要的答案,但我希望它能对您有所帮助。

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

关于c++ - Boost.asio和UNIX信号处理,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/7500054/

10-16 20:47