multithreading环境中的信号处理函数

在我的multithreadingGUI应用程序中,我有以下信号处理代码。 我想改进这个代码,以便它是正确的并且线程安全但是在信号处理方面有一些我不完全理解的东西:

  • 是在进程或线程级别处理的信号(我可以使用特定于线程的信号处理程序)吗?
  • 哪个线程上下文是signal_handler函数执行的?
  • 是否可以在短时间内发送许多SIGTERM信号?
  • 使用互斥锁来阻止signal_handler的并行执行是否有意义?

void signal_handler(int sig) { switch (sig) { case SIGTERM: ::wxLogMessage(wxT("SIGTERM signal received ...")); break; case SIGINT: ::wxLogMessage(wxT("SIGINT signal received ...")); break; case SIGUSR1: ::wxLogMessage(wxT("SIGUSR1 signal received ...")); break; default: ::wxLogMessage(wxT("Unknown signal received ...")); } // send wxCloseEvent to main application window ::wxGetApp().GetTopWindow()->Close(true); } 

我在init函数中注册信号处理程序:

 // register signal handlers signal(SIGTERM, signal_handler); signal(SIGINT, signal_handler); signal(SIGUSR1, signal_handler); 

要非常小心:正如信号(7)页面所说的那样,只有极少数函数( “异步信号安全”函数)可以(直接或间接)在信号处理程序中调用。 可能不应在信号处理程序中调用互斥相关函数。 又见pthreads(7)

您可以考虑在信号处理程序中设置volatile sigatomic_t变量, 并不时测试该标志的值。 如果你有C ++ 11(或C11)primefaces,例如C ++ 11 std :: atomic或C11 ,你就可以使那个volatile变量在这个意义上也是primefaces的。 然后使用primefaces加载工具对其进行测试。

Qt文档提出了以下技巧 :在启动时创建一个自我管道(2) ,然后让你的信号处理程序写入(2) ( write系统调用指定为async-signal-safe)单个(或更多)字节[ s]到同一进程的管道,并让你的GUI事件循环轮询(2)该管道的读取结束。

使用Qt处理信号的特定Linux的方法可能是使用signalfd(2)可能使用QSocketNotifier (尽管名称,它适用于可轮询文件描述符,而不仅仅是套接字)。 使用其他GUI工具包,您可能还可以添加要轮询的文件描述符(来自signalfdpipe signalfd )。

  • 信号处理程序是每进程状态 – 也就是说,进程中的所有线程共享同一组已安装的信号处理函数。
  • 信号掩码是每线程状态。 可以基于每个线程阻止或取消阻止信号。
  • 信号可以是流程或线程导向的。 如果信号是过程导向的,则选择当前没有阻塞信号类型的任意线程来处理它。

在multithreading应用程序中处理信号的一种简单方法是创建一个线程作为专用信号处理线程。 所有感兴趣的信号都在每个线程中被阻止; 没有建立信号处理程序; 并且信号处理线程在循环中调用sigwaitinfo() ,在收到信号时对其进行处理。

这意味着您不必担心要调用的函数是否是异步信号安全的 ,因为信号处理程序不处理信号 – 它们由专用信号处理线程同步处理,它可以调用它喜欢的任何函数(例如,它可以使用普通的pthreads同步函数来唤醒另一个线程)。

这个答案指的是POSIX线程( pthreads )。

参考1:

可以在线程级别处理信号,是的。 如果进程的多个线程处理信号并且信号被发送到进程,但是对于特定线程,则不确定哪个线程的处理程序将处理该信号。 (详见man pthread_kill()

参考2:

信号处理程序将在设置它的线程的上下文中执行。 这包括主线程。

参考3:

如果将相同类型的多个信号发送到同一进程,则它们可能在离开信号队列之前仅被压缩到一个信号中。 这是否可以区分到我不确定的线程级别,我不得不承认。

参考4:

如果游戏中涉及共享资源:是的,至少对于同时访问这些资源的处理程序代码的部分。 此外,这还取决于您尝试实施的逻辑。