【问题标题】:Signal handler behavior in multi threaded environment多线程环境中的信号处理程序行为
【发布时间】:2020-07-04 18:20:41
【问题描述】:

我有以下程序,其中只有一个线程安装信号处理程序。但是当我通过向每个线程发送信号来测试代码时,所有线程都执行信号处理程序。 所有线程是否共享相同的信号处理程序。我假设只有在产生这些线程的主进程安装信号处理程序时才会发生这种情况(线程共享信号处理程序)。

还有一个问题是关于信号处理程序执行的上下文。是否保证发送到特定线程的信号将在给定场景的相同线程上下文中执行?

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;
}

输出:

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

【问题讨论】:

标签: c linux multithreading pthreads signals


【解决方案1】:

来自manpage for signal(7)

信号处置是每个进程的属性:在多线程应用程序中,特定信号的处置对所有线程都是相同的。

所以所有线程共享相同的处理程序,是的。如果您使用pthread_kill() 向特定线程发送信号,则该线程应执行处理程序(当然,取决于使用pthread_sigmask() 设置的线程的信号掩码)。

另请注意,您不能在信号处理程序中安全地使用printf() 或其他标准输入输出函数。请参阅signal-safety(7) 中允许的函数列表。

【讨论】:

    【解决方案2】:

    所有线程共享信号处理程序。您可以使用 pthread_sigmask() 来选择哪些线程具有阻塞或未阻塞的信号,因此可以执行处理程序。如果多个线程有相同的信号解除阻塞,那么它们中的任何一个都可以执行处理程序。

    如此清理和修复的示例如下所示:

    #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;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-10-08
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-25
      相关资源
      最近更新 更多