Pthread Threads and Signals

POSIX threads and signals

  • What's the best way to control which thread
    a signal is delivered to?

As @zoli2k indicated, explicitly nominating a single thread to handle all signals you want handled (or a set of threads each with specific signal responsibilities), is a good technique.

  • What is the best way to tell another thread (that might actually be busy)
    that the signal has arrived?[...]
  • How can I safely handle passing the information that a signal has occurred
    to other threads? Does this need to happen in the signal handler?

I won't say "best," but here's my recommendation:

Block all desired signals in main, so that all threads are inherit that signal mask. Then, fashion the special signal receiving thread as a signal-driven event loop, dispatching newly arrived signals as some other intra-thread communication.

The simplest way to do this is to have the thread accept signals in a loop using sigwaitinfo or sigtimedwait. The thread then converts the signals somehow, perhaps broadcasting a pthread_cond_t, waking up other threads with more I/O, enqueuing a command in an application-specific thread-safe queue, whatever.

Alternatively, the special thread could allow signals to be delivered to a signal handler, unmasking for delivery only when ready to handle signals. (Signal delivery via handlers tends to be more error-prone than signal acceptance via the sigwait family, however.) In this case, the receiver's signal handler performs some simple and async-signal-safe action: setting sig_atomic_t flags, calling sigaddset(&signals_i_have_seen_recently, latest_sig), write() a byte to a non-blocking self-pipe, etc. Then, back in its masked main loop, the thread communicates receipt of the signal to other threads as above.

(UPDATED @caf rightly points out that sigwait approaches are superior.)

Signal handling in pthreads

There are several problems with your code:

  • ptr is not initialised, so all the ptr-> parts will crash the program
  • you are calling pthread_kill() immediately, very likely before the signal handler has been installed, and in a thread (which has unspecified behaviour)
  • you call printf() from a signal handler, which is not guaranteed to work (see man 7 signal for a list of safe functions)

This will work a lot better, though you'd still need proper thread synchronisation, and as stated elsewhere, you should use sigaction():

#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <string.h>

typedef struct data
{
char name[10];
int age;
}data;

void sig_func(int sig)
{
write(1, "Caught signal 11\n", 17);
signal(SIGSEGV,sig_func);
}

void func(data *p)
{
fprintf(stderr, "This is from thread function\n");
strcpy(p->name,"Mr. Linux");
p->age=30;
sleep(2); // Sleep to catch the signal
}

int main()
{
pthread_t tid;
pthread_attr_t attr;
data d;
data *ptr = &d;

signal(SIGSEGV,sig_func); // Register signal handler before going multithread
pthread_attr_init(&attr);
pthread_create(&tid,&attr,(void*)func,ptr);
sleep(1); // Leave time for initialisation
pthread_kill(tid,SIGSEGV);

pthread_join(tid,NULL);
fprintf(stderr, "Name:%s\n",ptr->name);
fprintf(stderr, "Age:%d\n",ptr->age);
}

Edit: install sighandler in main thread

Pthread threads and signals

Citing man pthreads

POSIX.1 distinguishes the notions of signals that are directed to the process as a whole and signals that are directed to individual threads. According to POSIX.1, a process-directed signal (sent using kill(2), for example) should be handled by a single, arbitrarily selected thread within the process.

There were some problems in Linux at days of glibc 2.2 and older (linuxthreads was used as pthread implementation); but since glibc 2.3-2.4 there is NPTL which is more accurate in POSIX conformance about signals.

I can only be sure that it will be delivered to one thread without this signal in signal mask?

If you are using kill - yes; to random thread which doesn't block this signal.

If so what about few signals that are delivered to particular thread, like 'SIGFPE', 'SIGSEGV',

They are delivered to particular thread, only when generated by CPU/kernel (by particular instruction in some context); not by kill utility with PID argument

if I will send them using kill shell command they will be delivered to random thread or will they be delivered to the thread that created other threads?

They will be delivered to random thread of process, kill usually sends process-wide signals. But if signal is deadly, all threads in process will be destroyed.

PS: http://www.linuxprogrammingblog.com/all-about-linux-signals?page=11

Signal receiver threads in C and pthread_join stalling program

You almost got it right. It is recommended to block the signals from the main thread to protect all new threads from mishandling the signal.

Any thread created after pthread_sigmask(), inherits the sigmask. The first parameter tells pthread_sigmask() what to do with the signals listed in the second parameter.

This line pthread_sigmask(SIG_BLOCK, &mask, NULL) should be placed in the main thread, not on the signal handler. Your original code will work too, but if the signal is sent to the wrong thread, it will kill the whole process.

In addition, the sender is sending signal faster than the receiver can handle. By sleeping for 1 second between each iteration, the receiver will be able to catch up.

I took the liberty and modified your code. I added some prints within the sender and receiver so you'll know what it is doing.

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

void receivetest(void); //function does not return anything
void signaltest(void); // does not accept parameter either.

int received = 0;
int sent = 0;
pthread_t signaler;
pthread_t receiver;
sigset_t mask;

int main(){

//setting up the signal mask
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &mask, NULL); //sets up the signal mask for this thread

//creation of both threads
pthread_create(&receiver, NULL, (void *)receivetest, NULL);
pthread_create(&signaler, NULL, (void *)signaltest, NULL);

pthread_join(signaler, NULL);
pthread_join(receiver, NULL);

//printing results after joining them back
printf("I'm the main function\n");
printf("Receieved: %d, sent: %d\n", received, sent);
return 0;

}

void signaltest(void){
int i = 0;
for(i=0;i<10;i++){ //sends 10 signals to receiver thread
printf("Sending signal\n");
pthread_kill(receiver, SIGUSR1);
sleep(1); // Don't send signals too fast
sent++;
}
}

void receivetest(void){
int c; //sigwait needs int
while(received < 10){ //waits for 10 signals and increments receieved
sigwait(&mask, &c);
printf("Signal received\n");
received++;
}
}

Output:

Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
I'm the main function
Receieved: 10, sent: 10

Unix pthreads and signals: per thread signal handlers

In addition to alk's answer:

You can use a per-thread function pointer to choose which function is executed when a certain signal is delivered, on a per-thread manner.

Note: Signals are delivered to any thread that is not explicitly blocking its delivery. This does not change that. You still need to use pthread_kill() or similar mechanisms to direct the signal to a specific thread; signals that are raised or sent to the process (instead of a specific thread), will still be handled by a random thread (among those that do not block it).

I cannot think of any use case where I'd personally prefer this approach; thus far there has always been some other way, something else easier and better. So, if you are considering implementing something like this for a real application, please step back and reconsider your application logic.

But, since the technique is possible, here's how I might implement it:

#include <signal.h>

/* Per-thread signal handler function pointer.
* Always use set_thread_SIG_handler() to change this.
*/
static __thread void (*thread_SIG_handler)(int, siginfo_t *, void *) = (void *)0;

/* Process-wide signal handler.
*/
static void process_SIG_handler(int signum, siginfo_t *info, void *context)
{
void (*func)(int, siginfo_t *, void *);

#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
func = __atomic_load_n(&thread_SIG_handler, __ATOMIC_SEQ_CST);
#else
func = __sync_fetch_and_add(&thread_SIG_handler, (void *)0);
#endif

if (func)
func(signum, info, context);
}

/* Helper function to set new per-thread signal handler
*/
static void set_thread_SIG_handler(void (*func)(int, siginfo_t *, void *))
{
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7)
__atomic_store_n(&thread_SIG_handler, func, __ATOMIC_SEQ_CST);
#else
void (*oldfunc)(int, siginfo_t *, void *);
do {
oldfunc = thread_SIG_handler;
} while (!__sync_bool_compare_and_swap(&thread_SIG_handler, oldfunc, func));
#endif
}

/* Install the process-wide signal handler.
*/
int install_SIG_handlers(const int signum)
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_sigaction = process_SIG_handler;
act.sa_flags = SA_SIGACTION;
if (sigaction(signum, &act, NULL))
return errno;
return 0;
}

I like the above because it does not require pthreads, and is very robust and reliable. Aside from the visual mess due to having that preprocessor logic to select which style of atomic built-ins are used, it's very simple too, if you look at it carefully.

GCC 4.7 and later provide C++11-like __atomic built-ins, older GCC versions and other compilers (ICC, Pathscale, Portland Group) provide __sync legacy built-ins. The __thread keyword for thread-local storage should similarly be available in all current POSIX-y systems.

If you have an archaic system, or insist on standards compliance, the following code should have roughly equivalent behaviour:

#include <pthread.h>
#include <signal.h>
#include <errno.h>

static pthread_key_t thread_SIG_handler_key;

static void process_SIG_handler(int signum, siginfo_t *info, void *context)
{
void (*func)(int, siginfo_t *, void *);

*((void **)&func) = pthread_getspecific(thread_SIG_handler_key);
if (func)
func(signum, info, context);
}

static int set_thread_SIG_handler(void (*func)(int, siginfo_t *, void *))
{
sigset_t block, old;
int result;

sigemptyset(&block);
sigaddset(&block, SIG); /* Use signal number instead of SIG! */
result = pthread_sigmask(SIG_BLOCK, &block, &old);
if (result)
return errno = result;

result = pthread_setspecific(thread_SIG_handler_key, (void *)func);
if (result) {
pthread_sigmask(SIG_SETMASK, &old, NULL);
return errno = result;
}

result = pthread_sigmask(SIG_SETMASK, &old, NULL);
if (result)
return errno = result;

return 0;
}

int install_SIG_handlers(const int signum)
{
struct sigaction act;
int result;

result = pthread_key_create(&thread_SIG_handler_key, NULL);
if (result)
return errno = result;

sigemptyset(&act.sa_mask);
act.sa_sigaction = process_SIG_handler;
act.sa_flags = SA_SIGACTION;
if (sigaction(signum, &act, NULL))
return errno;

return 0;
}

I think the closest real-life equivalent to code like this that I've actually ever used, is one where I used one realtime signal (SIGRTMIN+0) blocked in all but one thread, as a reflector: it sent another realtime signal (SIGRTMIN+1) to a number of worker threads, in order to interrupt blocking I/O. (It is possible to do this with a single realtime signal, but the two-signal model is simpler to implement and easier to maintain.)

Such signal reflection or fanout is sometimes useful, and it's not that different from this approach. Different enough to warrant its own question, though, if someone is interested.

Send and catch signals to pthreads in C

With POSIX threads, you have the functions pthread_cond_wait and pthread_cond_signal.

int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex)
int pthread_cond_signal(pthread_cond_t *cond)

The signaled thread should block on a pthread_cond_wait call until another thread sends a signal using pthread_cond_signal, with the same condition variable.

Considering the analogy with signals delivered to processes, this is a bit different because the signaled thread has already suspended its execution waiting for a signal, unlike a process that simply gets interrupted and goes on.

Are pthread condition signals the same or different from POSIX real-time signals?

Though the term "signal" is used when speaking of both mechanisms, POSIX realtime signals and pthread condition variables are different.

POSIX or operating signals are "software interrupts" with relatively rich semantics and history. They may be ignored (SIG_IGN), delivered (sa_sigaction), accepted, or blocked, except when they can't be. They may have their own stack for user-defined disposal, though what one can safely do during disposal is quite limited. They might take aim at an individual thread or at a whole process. They interrupt some functions, but not others, sometimes at the end-user's discretion (SA_RESTART). Realtime extensions allow signals to queue and perhaps deliver a word of data. There's more.

By contrast, POSIX pthread condition variables are synchronization mechanisms protecting some predicate. Here, the "signal" is the user-initiated action of waking one thread waiting on the condition variable, if such a thread exists.

It's perhaps unfortunate that the same term is used in different senses when we talk about these mechanisms, but so it is.

Signal handling among pthreads

  • Can signals [be] sent to all pthreads [and] be handled by more than one pthread at the same time?

Not at the same time. These are the possibilities:

  1. Send a signal to a process (kill()): In this case, any thread listening for the signal can receive it, but just one will do it.
  2. Send a signal to a process group: The signal will be delivered to all processes in the group.
  3. Send a signal to a specific thread (pthread_kill()): now you are sending it to a specific thread ID.

Prototype:

int pthread_kill(pthread_t thread, int sig);

In your case, I think the only way to deliver the signal to all threads is iterating along all your thread ids to send the signal with pthread_kill().

Signal handler behavior in multi threaded environment

From the manpage for signal(7):

The signal disposition is a per-process attribute: in a multithreaded application, the disposition of a particular signal is the same for all threads.

So all threads share the same handlers, yes. If you use pthread_kill() to send a signal to a specific thread, that thread should execute the handler (Depending on the thread's signal mask set with pthread_sigmask(), of course).

Also note that you can't safely use printf() or other stdio functions in a signal handler. See the list of allowed functions in signal-safety(7).



Related Topics



Leave a reply



Submit