简体   繁体   中英

Signal handler behavior in multi threaded environment

I have the following program where only one thread installs the signal handler. But when I tested the code by sending signal to each thread, all the threads execute the signal handler. Does all the threads share the same signal handler. I was under the assumption that it would happen(threads share signal handler) only when the main process which spawns these threads install the signal handler.

And one more question is about the context in which the signal handler executes. Is it guaranteed that the signal sent to the particular thread will execute in the same thread context for the given scenario?

void handler(int signo, siginfo_t *info, void *extra)
{
        printf("handler id %d and thread id %d\n",syscall( SYS_gettid ),pthread_self());
}
void signalHandler()
{
   struct sigaction sa;
   sa.sa_flags = SA_SIGINFO;
   sa.sa_sigaction = handler;
   sigaction(SIGSEGV, &sa, NULL);
   //sigaction(SIGINT, &sa, NULL);
}
void *threadfn0(void *p)
{
        signalHandler();
        printf("thread0\n");
        while ( 1 )
        {
                pause();
        }
}
void *threadfn1(void *p)
{
        while(1){
                printf("thread1\n");
                sleep(15);
        }
        return 0;
}
void *threadfn2(void *p)
{
        while(1){
                printf("thread2\n");
                sleep(15);
        }
        return 0;
}
int main()
{
        pthread_t t0,t1,t2;
        pthread_create(&t0,NULL,threadfn0,NULL);
        printf("T0 is %d\n",t0);
        pthread_create(&t1,NULL,threadfn1,NULL);
        printf("T1 is %d\n",t1);
        pthread_create(&t2,NULL,threadfn2,NULL);
        printf("T2 is %d\n",t2);
        sleep(10);
        pthread_kill(t2,SIGSEGV);
        sleep(10);
        pthread_kill(t1,SIGSEGV);
        pthread_join(t1,NULL);
        pthread_join(t2,NULL);
        pthread_join(t0,NULL);
        return 0;
}

output:

T0 is 1110239552
T1 is 1088309568
T2 is 1120729408
thread0
thread1
thread2
handler id 18878 and thread id 1120729408
thread2
thread1
handler id 18877 and thread id 1088309568
thread1

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) .

All threads share the signal handler. You can use pthread_sigmask() to select, which threads have which signals blocked or unblocked and therefore can execute the handler. If several threads have the same signal unblocked, then any of them can execute the handler.

So cleaned up and fixed example looks something like this:

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

static void handler (int signo, siginfo_t *info, void *extra)
{
    printf ("SIGNAL %u, handler id %lu and thread id %lu\n", signo, syscall (SYS_gettid), pthread_self ());
}

static void signalHandler (void)
{
   struct sigaction sa;
   sa.sa_flags = SA_SIGINFO;
   sa.sa_sigaction = handler;
   sigaction (SIGSEGV, &sa, NULL);
}

static void *threadfn0 (void *p)
{
    signalHandler ();

    sigset_t set;
    sigfillset (&set);
    pthread_sigmask (SIG_UNBLOCK, &set, NULL);

    printf ("thread0\n");
    while (1) {
        pause ();
    }
}

static void *threadfn1 (void *p)
{
    while (1) {
        printf ("thread1\n");
        sleep (15);
    }
    return 0;
}

static void *threadfn2 (void *p)
{
    while (1) {
        printf ("thread2\n");
        sleep (15);
    }
    return 0;
}

int main (int argc, char *argv[])
{
    pthread_t t0, t1, t2;

    // By default, block all signals in all threads and
    // unblock them only in one thread after signal handler
    // is set up, to avoid race conditions
    sigset_t set;
    sigfillset (&set);
    pthread_sigmask (SIG_BLOCK, &set, NULL);

    pthread_create (&t0, NULL, threadfn0, NULL);
    printf ("T0 is %lu\n", t0);
    pthread_create (&t1, NULL, threadfn1, NULL);
    printf ("T1 is %lu\n", t1);
    pthread_create (&t2, NULL, threadfn2, NULL);
    printf ("T2 is %lu\n", t2);

    pthread_kill (t2, SIGSEGV);
    pthread_kill (t1, SIGSEGV);
    pthread_kill (t0, SIGSEGV);

    pthread_join (t2, NULL);
    pthread_join (t1, NULL);
    pthread_join (t0, NULL);

    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM