2012-10-18 79 views
12

在我的多线程GUI应用程序中,我有以下信号处理代码。我想提高这个代码,以便它会是正确的,线程安全的,但有一些事情,我不完全理解的信号处理:多线程环境中的信号处理函数

  • 的信号在进程或线程级处理的(我可以有螺纹特定的信号处理程序)?
  • 其中线程上下文是执行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); 
} 

我注册信号处理程序在我的初始化函数:

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

回答

10

要非常小心:为signal(7)页告诉,只有极少数职能(“异步信号-safe“ ones)可以(直接或间接)在信号处理程序中调用。互斥信号相关功能可能不应该在信号处理程序中调用。另请参阅pthreads(7)

您可能会考虑在信号处理程序中设置volatile sigatomic_t变量,并不时测试该标志的值。 如果您有C++ 11(或C11)原子,例如C++ 11 std::atomic或C11 <stdatomic.h>,你可以使那volatile变量在这个意义上也是原子的。然后使用原子加载设施来测试它。

Qt文档暗示following trick:创建一个pipe(2)在启动时的自我,然后让你的信号处理write(2)(该write系统调用被指定为异步信号安全的)单一(或更多)字节[S],以一个管道到你的同一个进程,并让你的GUI事件循环poll(2)该管道的读取结束。处理与Qt的信号

一个Linux特有方式可能是可能使用signalfd(2)QSocketNotifier(尽管名称,它适用于可轮询的文件描述符,而不是只插座)。使用其他GUI工具包,您可能还可以添加要轮询的文件描述符(来自signalfdpipe)。

+2

注意在信号处理程序中使用std :: atomic并不能保证无锁实现。请参阅:http://www.informit.com/articles/article.aspx?p = 2204014 – Corvusoft

4

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

参考1:

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

参考2:

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

参考3:

如果相同类型的一个以上的信号被发送到它们可能在离开信号队列之前凝结成只有一个信号相同的处理。无论这可能与线程级别有所不同,我不得而知,我不得不承认。

参考4:

如果共享资源被参与游戏:是,至少对于处理程序代码访问这些资源并发的部分。此外,这也取决于您尝试实施的逻辑。

17
  • 信号处理程序是按进程状态的 - 也就是说,进程中的所有线程共享同一组已安装的信号处理函数。
  • 信号掩码是每线程状态。信号可以基于每个线程被阻塞或解除阻塞。
  • 信号可以是进程或线程指向的。如果一个信号是过程指向的,那么选择一个当前没有被阻塞的信号类型的任意线程来处理它。

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

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