• Linux多线程环境下信号处理机制


    //线程共享信号处理方式
    //线程独享各自的阻塞信号集
    
    //测试结果
    /*
    * 主线程 分线程 同时设置屏蔽字  发送信号 并没有被捕捉  =>正常 
    * 主线程 分线程 都没有设置屏蔽字 发送信号  主线程优先捕捉了信号一次
    * 主线程 先设置屏蔽字再创建分线程 分线程没有主动设置 发送信号  依然没有被捕捉=>但是因为主线程在设置屏蔽后才创建的分线程,分线程继承了主线程的屏蔽字,所以分线程虽然没有主动去设置屏蔽,但是其阻塞信号集里面依然是屏蔽的
    * 主线程 先创建分线程再设置屏蔽字 分线程 没有设置屏蔽 发送信号 被分线程捕捉了一次
    * 主线程 没有设置屏蔽 分线程设置屏蔽 发送信号  被主线程捕捉了一次
    */
    /*
    * 
    POSIX标准对多线程情况下的信号机制提出了一些要求:
    
    信号处理函数必须在多线程进程的所有线程之间共享, 但是每个线程要有自己的挂起信号集合和阻塞信号掩码。
    POSIX函数kill / sigqueue必须面向进程, 而不是进程下的某个特定的线程。
    每个发给多线程应用的信号仅递送给一个线程, 这个线程是由内核从不会阻塞该信号的线程中随意选出来的。
    如果发送一个致命信号到多线程, 那么内核将杀死该应用的所有线程, 而不仅仅是接收信号的那个线程。
    
    结论:
    1.sigaction注册时机
    sigaction不论在主线程中注册还是在子线程中注册,最终进程内的所有线程都调用sigaction注册的回调函数来处理。
    sigaction注册不同信号,则不同信号对应着sigaction注册时的回调函数
    sigaction注册相同信号,相同信号被注册多个回调函数,此时信号发来,执行的是最新的一个回调函数,等又有一个sigaction注册了之前的信号,则之前信号的回调函数会被更新会新的回调函数
    2.哪个线程处理信号
    如果主线程不阻塞某个信号,则优先处理信号的线程是主线程,且一个信号只会被一个线程所处理
    当主线程阻塞了某个信号,则交由子线程处理,通过多次测试得出,优先处理信号的线程是pthread_ID较大的那个
    虽然每个线程都有自己独立的signal mask,但是要注意子线程的mask是会从主线程继承而来的,如果主线程先阻塞了某个信号,再创建子线程,而子线程没有设置自己的signal mask ,则子线程也默认阻塞了该信号
    
    
    */
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    
    void PrintundoSignal(const char* str)
    {
        printf(str);
        sigset_t set;
        sigemptyset(&set);
        sigpending(&set);
    
        for (int i = 1; i < 32; ++i)
        {
            printf("signal%d state:%d\n", i, sigismember(&set, i));
        }
    }
    void Catch(int signo)
    {
        pthread_t pid = pthread_self();
        printf("%d signal is catched\n", signo);
       // PrintundoSignal("Catch");
    }
    void* thread(void*)
    {
        //设置线程的阻塞信号集
        printf(" this is thread \n");
        sigset_t set;
        sigemptyset(&set);
        sigaddset(&set, SIGUSR1);
    
    
        //将set信号集添加到信号阻塞集中
     //   sigprocmask(SIG_BLOCK, &set, NULL);
        PrintundoSignal("sign:thread");
        while (1)
        {
            sleep(1);
            printf("I am thread\n");
        }
        return nullptr;
    }
    int main(void)
    {
        int ret;
        struct sigaction act;
        struct sigaction old;
    
        //设置结构体的参数
        act.sa_handler = Catch;
        sigemptyset(&act.sa_mask);
        sigaddset(&act.sa_mask, SIGQUIT);
        act.sa_flags = 0;               //默认属性,信号捕捉函数执行期间,自动屏蔽本信号
    
        //注册捕捉函数
        ret = sigaction(SIGUSR1, &act, &old);
        if (ret < 0)
        {
            perror("sigaction error");
            exit(1);
        }
    
        //设置线程的阻塞信号集
    
        sigset_t set;
        sigemptyset(&set);
        sigaddset(&set, SIGUSR1);
    
    
     //   sigprocmask(SIG_BLOCK, &set, NULL);//此处设置再创建线程,分线程会继承主线程的阻塞信号集
    
        pthread_t tid;
        printf("main thread.\n");
        int  rc = pthread_create(&tid, NULL, thread, 0);
    
        //将set信号集添加到信号阻塞集中
        sigprocmask(SIG_BLOCK, &set, NULL);
        PrintundoSignal("sign:main");
    
        pthread_exit(0);
        while (1);
    
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
  • 相关阅读:
    linux中使用redshift进行防蓝光
    如何画一棵树
    LeetCode刷题记录1720.解码异或后的数组
    防止请求重复提交:注解+拦截器的实现方案
    无涯教程-JavaScript - ISREF函数
    技术管理杂谈
    SpringBoot项目基础git
    模板方法模式:封装不变步骤,引导扩展实现灵活多态的算法流程
    自定义注解和@Target、@Retention注解的使用
    Linux环境 redis完整配置及启动命令
  • 原文地址:https://blog.csdn.net/weixin_43698578/article/details/126405643