Detailed use of pthread_sigmask

c/c++


Article directory


foreword

For thread signals, you should forget about signal / sigaction, they are only designed for single process single thread

pthread_sigmask is similar to sigprocmask;

sigprocmask can only be used for single process and single thread; fork's child process has a copy of the shielded signal;

pthread_sigmask is used for multithreading; the new thread has a copy of the shielded signal of the thread that pthread_create;

For the processing of thread signals, it is best to use one thread for unified processing and comparison, otherwise it will be too messy!

Regarding thread safety and reentrancy, there are two concepts: thread safety and reentrancy

Do not use sigaction / signal to process signals in multi-threads, otherwise you have to consider reentrancy, thread safety and other issues, which is too troublesome; and these two functions are process-wide;

All the following codes use sigwait [signal synchronization, no longer call the registration function]

You can also use sigwaitinfo, usage instructions: sigwaitinfo

1. About sigwait / sigwaitinfo This synchronization method generally needs to block the signal first, otherwise check the pending signal, different linux versions have different processing methods, the specific situation is still in the man 2. If you read the following code
or If you don't know the way of synchronizing signals, you can refer to the message mechanism of windows;

The first example replaces 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;
}

In the second example, let the child thread handle the signal; ctrl+c triggers it, and the signal is sent to the process.
If the code commented below is opened, two threads can handle the signal. Which thread should be used? Generally, the main Thread
Why is it the main thread? Threads under linux are implemented by processes

#include "util.h"
#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
 
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;
}

In the third example, the main thread calls alarm, let the sub-thread handle it, and ctrl+c ends;
all signals are blocked, and they are no longer added one by one, which is troublesome

 
#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
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;
}

In the fourth example, there are 3 threads in total. The main thread is the same as above, calling alarm every second, a thread dedicated to signal processing, and a worker thread;

#include <signal.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <sys/types.h>
#include <sys/wait.h>
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;
}

Guess you like

Origin blog.csdn.net/zyq880625/article/details/132046697