【问题标题】:signal handler function in multithreaded environment多线程环境中的信号处理函数
【发布时间】:2012-10-08 18:29:04
【问题描述】:

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

【问题讨论】:

    标签: c++ c multithreading signal-handling


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

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

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

    【讨论】:

    • 我在一个项目中使用了这种方法,效果很好
    【解决方案2】:

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

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

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

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

    【讨论】:

    【解决方案3】:

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

    参考1:

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

    参考2:

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

    参考 3:

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

    参考 4:

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

    【讨论】:

      猜你喜欢
      • 2020-07-04
      • 1970-01-01
      • 2012-07-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多