pthread_sigmask使用详解

c/c++


文章目录

  • c/c++
  • 前言


前言

对于线程信号,你应该忘记signal / sigaction ,他们只为单进程单线程设计

pthread_sigmask 跟 sigprocmask 类似;

sigprocmask 只能用于单进程单线程; fork的子进程拥有一份屏蔽信号拷贝;

pthread_sigmask 用于多线程 ; 新线程拥有一份pthread_create那个线程的屏蔽信号拷贝;

对于线程信号的处理 , 最好还是用一个线程来统一处理比较, 否则太乱啦!

关于线程安全和可重入, 完全2个概念: 线程安全 可重入

在多线程中处理信号 就别用sigaction / signal 了, 不然还得考虑重入,线程安全等问题,太麻烦;,而且这2个函数都是进程范围的;

下面所有代码中用到了sigwait [ 信号同步化, 不再调用注册函数了]

你也可以用sigwaitinfo , 用法说明 : sigwaitinfo

1.关于sigwait / sigwaitinfo 这种同步化的方式一般要先block信号, 否则还检查啥pendding信号呢 ,不同的linux版本有不同的处理方式, 具体情况还是看man把
2.如果看了下面代码还是不了解同步化信号的方式 , 可以参考windows的消息机制 ;

第一个例子 替换 sigprocmask:

//gcc 别忘了 -lpthread
void handler(int s){
    printf("handler :%d\n" ,s);
}
 
int main(int argc, char**argv)
{
    signal(SIGINT , handler);
    sigset_t mask;
    sigaddset(&mask , SIGINT);
    pthread_sigmask(SIG_BLOCK,&mask, NULL); //替换sigprocmask
 
    //用ctrl+\ 终止
    while(1)
        pause();
    return 0;
}

第2个例子 , 让子线程处理信号; ctrl+c 触发他 , 此信号发送给进程的
如果把下面注释的代码打开 , 则有2个线程都能处理信号, 到底用哪个线程 ? 一般情况下主线程
为什么是主线程 ? linux下的线程由进程实现

#include "util.h"
#include 
#include 
#include 
#include 
#include 
 
static void * t1(void *arg){
    sigset_t * mask = (sigset_t *)arg;
    int sig = 0;
 
    while(1){
        if ( sigwait(mask,&sig)  != 0 ){
            perror(" thread sigwait :");
            continue;
        }
        printf("thread got signal : %d\n" , sig);
    }
}
 
int main(int argc, char**argv)
{
    sigset_t mask;
    sigaddset(&mask , SIGINT);
    pthread_sigmask(SIG_BLOCK,&mask, NULL);
    pthread_t t;
    pthread_create(&t,0,t1,&mask);
 
    int sig = 0;
    
    while(1) pause();
 
    /*
    while(1){
        if ( sigwait(&mask,&sig)  != 0 ){
            perror("sigwait :");
            continue;
        }
        printf(" ! main got signal : %d\n" , sig);
    }
    */
 
    return 0;
}

第3个例子 ,主线程调用alarm , 让子线程去处理 , ctrl+c 结束;
屏蔽了所有信号,不再一个个加了,麻烦

 
#include 
#include 
#include 
#include 
#include 
volatile sig_atomic_t goon = 1;
 
static void * t1(void *arg){
    sigset_t * mask = (sigset_t *)arg;
    int sig = 0;
 
    while(1){
        if ( sigwait(mask,&sig)  != 0 ){
            perror(" thread sigwait :");
            continue;
        }
        printf("thread got signal : %d\n" , sig);
        if(SIGINT == sig){
            goon = 0;
            break;
        }
    }
}
 
int main(int argc, char**argv)
{
    sigset_t mask;
    sigfillset(&mask); //屏蔽所有信号
    pthread_sigmask(SIG_BLOCK,&mask, NULL);
    pthread_t t;
    pthread_create(&t,0,t1,&mask);
 
    int sig = 0;
    while(goon){
        alarm(1);
        sleep(1);
    }
 
    pthread_join(t,0);
    puts("end");
    return 0;
}

第4个例子 , 一共3个线程, 主线程跟上面一样,每秒调用alarm , 一个专门处理信号的线程 , 还有一个工作线程;

#include 
#include 
#include 
#include 
#include 
volatile sig_atomic_t goon = 1;
 
static void * worker (void *arg){
    while(goon){
        printf("worker is running , tid:%ld\n" , pthread_self());
        sleep(5);
    }
    puts("worker is done");
}
 
static void * sig_handler_thread(void *arg){
    sigset_t * mask = (sigset_t *)arg;
    int sig = 0;
    pthread_t tid = pthread_self();
    while(1){
        if ( sigwait(mask,&sig)  != 0 ){
            printf("sigwait error : %s\n" , strerror(errno));
            continue;
        }
        printf("thread :%ld got signal : %d\n" , tid,sig);
        if(SIGINT == sig){
            goon = 0;
            break;
        }
    }
}
 
int main(int argc, char**argv)
{
    sigset_t mask;
    sigfillset(&mask);
    pthread_sigmask(SIG_BLOCK,&mask, NULL);
    pthread_t tid1, tid2;
    pthread_create(&tid1,0,sig_handler_thread,&mask);
    pthread_create(&tid2,0,worker,NULL);
 
    int sig = 0;
    while(goon){
        alarm(1);
        sleep(1);
    }
 
    pthread_join(tid2,0);
    pthread_join(tid1, NULL);
    puts("end");
    return 0;
}

你可能感兴趣的:(C/C++,c++)