简体   繁体   English

多线程环境中的信号处理函数

[英]signal handler function in multithreaded environment

In my multithreaded GUI application I have the following signal handling code.在我的多线程 GUI 应用程序中,我有以下信号处理代码。 I want to improve this code so that it will be correct and threading safe but there are some things I don't fully understand in signal handling:我想改进这段代码,使其正确且线程安全,但在信号处理中有些事情我不完全理解:

  • is signal handled at the process or thread level (can I have thread-specific signal handlers)?信号是在进程级还是线程级处理的(我可以有特定于线程的信号处理程序)吗?
  • in which thread context is signal_handler function executed? signal_handler 函数在哪个线程上下文中执行?
  • is it possible to send many SIGTERM signals in a short time?是否可以在短时间内发送多个 SIGTERM 信号?
  • does it make sense to use a mutex to prevent parallel execution of signal_handler?使用互斥锁来防止并行执行 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);
}

I register signal handlers in my init function:我在我的 init 函数中注册了信号处理程序:

// register signal handlers
signal(SIGTERM, signal_handler);
signal(SIGINT,  signal_handler);
signal(SIGUSR1, signal_handler);
  • Signal handlers are per-process state - that is, all the threads in a process share the same set of installed signal handler functions.信号处理程序是每个进程的状态——也就是说,一个进程中的所有线程共享同一组已安装的信号处理程序函数。
  • Signal masks are per-thread state.信号掩码是每个线程的状态。 Signals can be blocked or unblocked on a per-thread basis.信号可以在每个线程的基础上被阻塞或解除阻塞。
  • Signals can be process- or thread-directed.信号可以是进程导向的或线程导向的。 If a signal is process-directed, then an arbitrary thread which does not currently have the signal type blocked is chosen to handle it.如果信号是面向进程的,则选择当前没有阻塞信号类型的任意线程来处理它。

A simple way to handle signals in a multi-threaded application is to create one thread as a dedicated signal-handling thread.在多线程应用程序中处理信号的一种简单方法是创建一个线程作为专用信号处理线程。 All signals of interest are blocked in every thread;所有感兴趣的信号都在每个线程中被阻塞; no signal handlers are established;没有建立信号处理程序; and the signal-handling thread calls sigwaitinfo() in a loop, acting on the signals as they're received.并且信号处理线程在循环中调用sigwaitinfo() ,在收到信号时对其进行处理。

This means that you don't need to worry about whether the functions you want to call are async-signal-safe or not, because signals aren't handled in signal handlers - they're handled synchronously by your dedicated signal-handling thread, which can call any function it likes (for example, it can use the ordinary pthreads synchronisation functions to wake up another thread).这意味着您无需担心要调用的函数是否是异步信号安全的,因为信号不是在信号处理程序中处理的——它们是由您专用的信号处理线程同步处理的,它可以调用它喜欢的任何函数(例如,它可以使用普通的 pthreads 同步函数来唤醒另一个线程)。

Be very careful: as the signal(7) page is telling, only very few functions (the "async-signal-safe" ones, see signal-safety(7) for more) can be (directly or indirectly) called inside signal handlers.要非常小心:正如signal(7)页面所说,只有很少的函数( “async-signal-safe”函数,更多信息请参见signal-safety(7) )可以(直接或间接)在信号处理程序中调用. Mutex related functions probably should not be called in signal handlers.可能不应该在信号处理程序中调用与互斥锁相关的函数。 See also pthreads(7)另见pthreads(7)

You might consider setting a volatile sigatomic_t variable in your signal handler, and test the value of that flag from time to time.您可能会考虑在信号处理程序中设置一个volatile sigatomic_t变量,并时常测试该标志的值。 If you have C++11 (or C11) atomics, eg C++11 std::atomic or C11 <stdatomic.h> , you could make that volatile variable also atomic in that sense.如果您有 C++11(或 C11)原子,例如 C++11 std::atomic或 C11 <stdatomic.h> ,您可以使该volatile变量在这个意义上也是原子的。 Then use the atomic load facilities to test it.然后使用原子加载工具对其进行测试。

The Qt documentation suggests the following trick : create a pipe(2) to self at startup, then have your signal handler write(2) (the write syscall is specified as being async-signal-safe) a single (or more) byte[s] to a pipe to your same process, and have your GUI event loop poll(2) the read end of that pipe. Qt 文档建议使用以下技巧:在启动时创建一个管道 (2)到自身,然后让您的信号处理程序写入 (2)write系统调用被指定为异步信号安全的)单个(或多个)字节[ s] 到你的同一个进程的管道,并让你的 GUI 事件循环轮询(2)该管道的读取端。

A Linux-specific way to handle signals with Qt might be to use signalfd(2) probably with QSocketNotifier (despite the name, it works on pollable file descriptors, not only sockets).使用 Qt 处理信号的特定于 Linux 的方法可能是将signalfd(2)QSocketNotifier一起使用(尽管名称如此,它适用于可轮询的文件描述符,而不仅仅是套接字)。 With other GUI toolkits, you probably can also add a file descriptor (the one from signalfd or pipe ) to be polled.使用其他 GUI 工具包,您可能还可以添加要轮询的文件描述符(来自signalfdpipe的描述符)。

This answer refers to POSIX threads ( pthreads ).这个答案指的是 POSIX 线程 ( pthreads )。

Referring 1:参考 1:

Signals could be handled on thread level, yes.信号可以在线程级别处理,是的。 If more than one thread of a process handles a signal and the signal ist sent to the process, but to a specific thread it is not determined which thread's handler will handle the signal.如果一个进程的多个线程处理一个信号,并且信号被发送到进程,但发送到特定线程,则不确定哪个线程的处理程序将处理该信号。 (see man pthread_kill() for details) (详见man pthread_kill()

Referring 2:参考2:

The signal handler will be excuted in the context of the thread which set it.信号处理程序将在设置它的线程的上下文中执行。 This includes the main thread.这包括主线程。

Referring 3:参考 3:

If more than one signal of the same type is sent to the same process they might be condensed in into only one signal before leaving the signal queue.如果同一类型的多个信号被发送到同一进程,它们可能会在离开信号队列之前被压缩成只有一个信号。 Whether this could be differentiate to the thread level I do not know for sure, I have to admit.这是否可以区分到我不确定的线程级别,我不得不承认。

Referring 4:参考 4:

If shared resources are involved in the game: yes, at least for the parts of the handlers' code accessing those resources concurrently.如果游戏中涉及共享资源:是的,至少对于同时访问这些资源的处理程序代码部分而言。 And moreover this also depends on the logic you try to implement.此外,这还取决于您尝试实现的逻辑。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM