[英]signal handler function in multithreaded environment
在我的多线程 GUI 应用程序中,我有以下信号处理代码。 我想改进这段代码,使其正确且线程安全,但在信号处理中有些事情我不完全理解:
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);
在多线程应用程序中处理信号的一种简单方法是创建一个线程作为专用信号处理线程。 所有感兴趣的信号都在每个线程中被阻塞; 没有建立信号处理程序; 并且信号处理线程在循环中调用sigwaitinfo()
,在收到信号时对其进行处理。
这意味着您无需担心要调用的函数是否是异步信号安全的,因为信号不是在信号处理程序中处理的——它们是由您专用的信号处理线程同步处理的,它可以调用它喜欢的任何函数(例如,它可以使用普通的 pthreads 同步函数来唤醒另一个线程)。
要非常小心:正如signal(7)页面所说,只有很少的函数( “async-signal-safe”函数,更多信息请参见signal-safety(7) )可以(直接或间接)在信号处理程序中调用. 可能不应该在信号处理程序中调用与互斥锁相关的函数。 另见pthreads(7)
您可能会考虑在信号处理程序中设置一个volatile sigatomic_t变量,并时常测试该标志的值。 如果您有 C++11(或 C11)原子,例如 C++11 std::atomic或 C11 <stdatomic.h>
,您可以使该volatile
变量在这个意义上也是原子的。 然后使用原子加载工具对其进行测试。
Qt 文档建议使用以下技巧:在启动时创建一个管道 (2)到自身,然后让您的信号处理程序写入 (2) ( write
系统调用被指定为异步信号安全的)单个(或多个)字节[ s] 到你的同一个进程的管道,并让你的 GUI 事件循环轮询(2)该管道的读取端。
使用 Qt 处理信号的特定于 Linux 的方法可能是将signalfd(2)与QSocketNotifier一起使用(尽管名称如此,它适用于可轮询的文件描述符,而不仅仅是套接字)。 使用其他 GUI 工具包,您可能还可以添加要轮询的文件描述符(来自signalfd
或pipe
的描述符)。
这个答案指的是 POSIX 线程 ( pthreads
)。
参考 1:
信号可以在线程级别处理,是的。 如果一个进程的多个线程处理一个信号,并且信号被发送到进程,但发送到特定线程,则不确定哪个线程的处理程序将处理该信号。 (详见man pthread_kill()
)
参考2:
信号处理程序将在设置它的线程的上下文中执行。 这包括主线程。
参考 3:
如果同一类型的多个信号被发送到同一进程,它们可能会在离开信号队列之前被压缩成只有一个信号。 这是否可以区分到我不确定的线程级别,我不得不承认。
参考 4:
如果游戏中涉及共享资源:是的,至少对于同时访问这些资源的处理程序代码部分而言。 此外,这还取决于您尝试实现的逻辑。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.