Say I have a Thread A, which wants to send signals to Threads B, C and D. Can I do something like this.
SendSignalTo( ThreadB, SIGUSR1 );
SendSignalTo( ThreadC, SIGUSR1 );
SendSignalTo( ThreadD, SIGUSR1 );
With SIGUSR1 signal handler, defined differently for Thread B, C and D, like as follows.
void SIGUSR1_Handler_for_ThreadB(...){...}
void SIGUSR1_Handler_for_ThreadC(...){...}
void SIGUSR1_Handler_for_ThreadD(...){...}
And if not, what is the alternative.
You can send a signal to a specific thread using pthread_kill()
, or if you don't mind being GNU-specific, using pthread_sigqueue()
(which can specify one int
or void *
the handler can access via info->si_value
).
There is only one signal handler per signal for the process. This means that a specific signal will always call the same handler function, no matter which thread it happens to be. If one thread sets a new signal handler, the signal handler will change for all threads.
However, the workaround is trivial: use a per-thread function pointer to define which function the signal handler should call. Just remember the signal handler limitations -- you can only use async-signal safe functions in a signal handler.
/* Simplify by defining the signal handler function type, assume SA_SIGINFO */
typedef void (*signal_handler_t)(int, siginfo_t *, void *);
/* Per-thread variable pointing to the desired function */
static __thread signal_handler_t thread_handler = NULL;
/* Process-wide actual signal handler */
static void signal_handler(int signum, siginfo_t *info, void *context)
{
signal_handler_t func;
func = __sync_fetch_and_or(&thread_handler, (signal_handler_t)0);
if (func)
func(signum, info, context);
}
The atomic load (__sync_fetch_and_or()
) allows you to trivially change the per-thread handler using a simple atomic store at any point in time, without even blocking the signal. Switching to function new_thread_handler
is then
signal_handler_t func;
do {
func = thread_handler;
} while (!__sync_bool_compare_and_swap(&thread_handler, func, new_thread_handler));
The __sync_fetch_and_or()
and the function switch can both be replaced by one C++11-style __atomic_
call, but I don't have a GCC recent enough yet, so I'm still using the old-style __sync_
calls.
POSIX also supports real-time signals, SIGRTMIN+0
, SIGRTMIN+1
, .., SIGRTMAX
. They have the added benefit that more than one of them can be pending at the same time. They are much better suited for this kind of thing than the traditional signals.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With