Signalling all threads in a process
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.
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...)
In multithreaded program raise(sig) is equivalent to pthread_kill(pthread_self(), sig). Try kill(getpid(), sig)
Given that you can apparently lock thread creation and destruction, could you not just have the "broadcasting" thread post the required updates to thread-local-state in a per-thread queue, which each thread checks whenever it goes to use the thread-local-state? If there's outstanding update(s), it first applies them.
链接地址: http://www.djcxy.com/p/50020.html上一篇: 在Linux上如何执行异步信号处理程序?
下一篇: 指示进程中的所有线程