15

在我的多线程 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);
}

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

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

3 回答 3

25
  • 信号处理程序是每个进程的状态——也就是说,一个进程中的所有线程共享同一组已安装的信号处理程序函数。
  • 信号掩码是每个线程的状态。信号可以在每个线程的基础上被阻塞或解除阻塞。
  • 信号可以是进程导向的或线程导向的。如果信号是进程导向的,则选择当前没有阻塞信号类型的任意线程来处理它。

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

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

于 2012-10-18T11:02:03.830 回答
15

要非常小心:正如signal(7)页面所说,只有很少的函数(“异步信号安全”函数,请参阅signal-safety(7)了解更多信息)可以(直接或间接)在信号处理程序内部调用. 可能不应该在信号处理程序中调用 Mutex 相关函数。另请参见pthreads(7)

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

Qt 文档建议了以下技巧:在启动时创建一个管道(2)到 self,然后让你的信号处理程序write(2)write系统调用被指定为异步信号安全)单个(或更多)字节 [s ] 到同一进程的管道,并让您的 GUI 事件循环poll(2)该管道的读取端。

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

于 2012-10-18T10:18:34.530 回答
5

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

参考1:

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

参考2:

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

参考3:

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

参考4:

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

于 2012-10-18T10:25:59.010 回答