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

//线程共享信号处理方式
//线程独享各自的阻塞信号集

//测试结果
/*
* 主线程 分线程 同时设置屏蔽字  发送信号 并没有被捕捉  =>正常 
* 主线程 分线程 都没有设置屏蔽字 发送信号  主线程优先捕捉了信号一次
* 主线程 先设置屏蔽字再创建分线程 分线程没有主动设置 发送信号  依然没有被捕捉=>但是因为主线程在设置屏蔽后才创建的分线程,分线程继承了主线程的屏蔽字,所以分线程虽然没有主动去设置屏蔽,但是其阻塞信号集里面依然是屏蔽的
* 主线程 先创建分线程再设置屏蔽字 分线程 没有设置屏蔽 发送信号 被分线程捕捉了一次
* 主线程 没有设置屏蔽 分线程设置屏蔽 发送信号  被主线程捕捉了一次
*/
/*
* 
POSIX标准对多线程情况下的信号机制提出了一些要求:

信号处理函数必须在多线程进程的所有线程之间共享, 但是每个线程要有自己的挂起信号集合和阻塞信号掩码。
POSIX函数kill / sigqueue必须面向进程, 而不是进程下的某个特定的线程。
每个发给多线程应用的信号仅递送给一个线程, 这个线程是由内核从不会阻塞该信号的线程中随意选出来的。
如果发送一个致命信号到多线程, 那么内核将杀死该应用的所有线程, 而不仅仅是接收信号的那个线程。

结论:
1.sigaction注册时机
sigaction不论在主线程中注册还是在子线程中注册,最终进程内的所有线程都调用sigaction注册的回调函数来处理。
sigaction注册不同信号,则不同信号对应着sigaction注册时的回调函数
sigaction注册相同信号,相同信号被注册多个回调函数,此时信号发来,执行的是最新的一个回调函数,等又有一个sigaction注册了之前的信号,则之前信号的回调函数会被更新会新的回调函数
2.哪个线程处理信号
如果主线程不阻塞某个信号,则优先处理信号的线程是主线程,且一个信号只会被一个线程所处理
当主线程阻塞了某个信号,则交由子线程处理,通过多次测试得出,优先处理信号的线程是pthread_ID较大的那个
虽然每个线程都有自己独立的signal mask,但是要注意子线程的mask是会从主线程继承而来的,如果主线程先阻塞了某个信号,再创建子线程,而子线程没有设置自己的signal mask ,则子线程也默认阻塞了该信号


*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
#include <pthread.h>
#include <string.h>
#include <errno.h>


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

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值