Pretty much - don't - dealing with shared data in a signal handler almost always leads to a world of pain, dealing with threads as well and you got yourself a mess.
By default a signal is blocked while the signal handler is running (at least on linux, that might not be universally true), so at least the signal handler will not be preempted by itself. Though, if you have multiple threads, and the signal is not blocked in the other threads, a signal handler might very well be run concurrently within several threads.
One thread will receive the signal and execute the handler, it's more or less random which thread that'll be, although you could control it by blocking the signal in all threads you don't want to handle the signal.
However, any of the other threads bar the one handling the signal might run in parallell. The thread handling a signal could run the signal handler at pretty much any point in the program (as long as the signal isn't blocked.) So, you'd need some sort of locking to protect that data. The problem is you can't use any of the normal thread locking primitives, they are not signal async safe. Meaning if you e.g. try to grab a pthread_mutex_t in a signal handler, you easily deadlock your program.
The only functions you can safely call in a signal handler are the ones listed here .
With regards to protecting the shared data, you could use sigblock()/sigunblock() as a sort of protection, ensuring the signal handler doesn't run while you're accessing that shared data - and the signal have to blocked in all the threads, otherwise it'll just run within one of the threads that doesn't have it blocked - going down that road is madness.
Pretty much the only shared data you can safely access in a signal handler is a sig_atomic_t
type, in practice other kinds of primitive types usually safe too.
What you really should do in a signal handler is just
- set a global flag
- check that flag elsewhere in code when suitable, and take action
Or
- have some sort of main loop that monitors file descriptors for events using select()/poll() or similar.
- create a pipe and monitor that in your main loop
- write() a byte to a pipe in your signal handler
- run your code to deal with the signal, including protecting any shared data when the mainloop detects an event on that pipe
Or
- Keep a spare thread around
- block the given signal in all your threads
- have that spare thread loop on calling sigsuspend() with a signal mask ensuring delivery of that signal.
- run your code, including protecting any shared data to deal with the signal when sigsuspend() returns