问题
In my multithreaded GUI application I have the following signal handling code. 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 ?
- is it possible to send many SIGTERM signals in a short time ?
- does it make sense to use a mutex to prevent parallel execution of 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:
// register signal handlers
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);
回答1:
Be very careful: as the signal(7) page is telling, only very few functions (the "async-signal-safe" ones) can be (directly or indirectly) called inside signal handlers. Mutex related functions probably should not be called in signal handlers. See also 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.
If you have C++11 (or C11) atomics, e.g. C++11 std::atomic or C11 <stdatomic.h>, you could make that volatile
variable also atomic in that sense. 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.
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). With other GUI toolkits, you probably can also add a file descriptor (the one from signalfd
or pipe
) to be polled.
回答2:
- 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.
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).
回答3:
This answer refers to POSIX threads (pthreads
).
Referring 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)
Referring 2:
The signal handler will be excuted in the context of the thread which set it. This includes the main thread.
Referring 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:
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.
来源:https://stackoverflow.com/questions/12952262/signal-handler-function-in-multithreaded-environment