Without keeping a list of current threads, I'm trying to see that a realtime signal gets delivered to all threads in my process. My idea is to go about it like this:
pthread_sigmask
) for itself, and enters a loop repeatedly calling raise(sig)
until sigpending
indicates that the signal is pending (there were no threads remaining with the signal blocked).The problem I'm running into is that pthread_sigmask
is not being respected. Everything works right if I run the test program under strace
(presumably due to different scheduling timing), but as soon as I run it alone, the sender receives its own signal (despite having blocked it..?) and none of the other threads ever get scheduled.
Any ideas what might be wrong? I've tried using sigqueue
instead of raise
, probing the signal mask, adding sleep
all over the place to make sure the threads are patiently waiting for their signals, etc. and now I'm at a loss.
Edit: Thanks to psmears' answer, I think I understand the problem. Here's a potential solution. Feedback would be great:
num_threads
signals to the process, then unblocks the signal for itself.num_threads
to return.num_threads
, then it releases the lock.One possible concern is that the signals will not get queued if the kernel is out of memory (Linux seems to have that issue). Do you know if sigqueue
reliably informs the caller when it's unable to queue the signal (in which case I would loop until it succeeds), or could signals possibly be silently lost?
Edit 2: It seems to be working now. According to the documentation for sigqueue
, it returns EAGAIN
if it fails to queue the signal. But for robustness, I decided to just keep calling sigqueue
until num_threads-1
signal handlers are running, interleaving calls to sched_yield
after I've sent num_threads-1
signals.
There was a race condition at thread creation time, counting new threads, but I solved it with a strange (ab)use of read-write locks. Thread creation is "reading" and the broadcast signal is "writing", so unless there's a thread trying to broadcast, it doesn't create any contention at thread-creation.
The common ways of signalling are through WaitHandle and Monitor , that can coordinate between threads by notifying (signal) them when to go ahead and when to halt. All the EventWaitHandle mentioned below are basically WaitHandle objects that can signal and wait for signals.
A process-directed signal may be delivered to any one of the threads that does not currently have the signal blocked. If more than one of the threads has the signal unblocked, then the kernel chooses an arbitrary thread to which to deliver the signal.
signal is a per process call, not a per thread one, if you call it it sets the handler for all threads in the process. Signals and threads is a complex topic. You might be better off asking about what you really what to do. Using signal in a multithreaded program is essentially undefined behaviour.
Signals sent to any thread are considered as signal sent to the main process. Thus, if a thread gets a signal, it is quite possible that an other thread will execute the handler.
raise()
sends the signal to the current thread (only), so other threads won't receive it. I suspect that the fact that strace
makes things work is a bug in strace
(due to the way it works it ends up intercepting all signals sent to the process and re-raising them, so it may be re-raising them in the wrong way...).
You can probably get round that using kill(getpid(), <signal>)
to send the signal to the current process as a whole.
However, another potential issue you might see is that sigpending()
can indicate that the signal is pending on the process before all threads have received it - all that means is that there is at least one such signal pending for the process, and no CPU has yet become available to run a thread to deliver it...
Can you describe more details of what you're aiming to achieve? And how portable you want it to be? There's almost certainly a better way of doing it (signals are almost always a major headache, especially when mixed with threads...)
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