• Linux--信号阻塞与屏蔽


    1. sigprocmask函数提供屏蔽和解除屏蔽信号的功能。 
    从而实现关键代码的运行不被打断。 
    函数声明如下:

      int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    其中参数 how可设置的参数为:SIG_BLOCK, SIG_UNBLOCK,SIG_SETMASK 
    SIG_BLOCK: 
    按照参数 set 提供的屏蔽字,屏蔽信号。并将原信号屏蔽保存到oldset中。 
    SIG_UNBLOCK: 
    按照参数 set 提供的屏蔽字进行信号的解除屏蔽。针对Set中的信号进行解屏。 
    SIG_SETMASK: 
    按照参数 set 提供的信号设置重新设置系统信号设置。

    2. 信号屏蔽与解屏常见实现 
    方法一: SIG_BLOCK, SIG_UNBLOCK成对实现 
    优点oldset可以不管。

    方法二: 
    SIG_BLOCK设置屏蔽,保存原有信号设置。 
    SIG_SETMASK重新恢复原有设置。

    3. 屏蔽过程中接受到的信号如何处理 
    在信号屏蔽过程中,出现的所有被屏蔽的信号,不管发生多少次,在信号解除屏蔽后,系统会执行一次被屏蔽信号上的操作。

    #include<stdio.h>
    #include<signal.h>
    #include<unistd.h>
    
    int flag_sigusr1 = 0;
    int flag_sigusr2 = 0;
    
    void sig_usr1(int signo)
    {
        fprintf(stdout, "caught SIGUSR1
    ");
        flag_sigusr1 = 1;
        return;
    }
    
    void sig_usr2(int signo)
    {
        fprintf(stdout, "caught SIGUSR2
    ");
        flag_sigusr2 = 1;
        return;
    }
    
    int main(void){
        sigset_t newmask, oldmask;
        signal(SIGUSR1, sig_usr1);
        signal(SIGUSR2, sig_usr2);
    
        fprintf(stdout, "catch sigusr1 can break
    ");
    	
        while(1)
    	{
            if(flag_sigusr1)
    		{
                fprintf(stdout, "break
    ");
                break;
            }
            sleep(5);
        }
    	fprintf(stdout, "first while was broken
    ");
    	
    	//重新设置为0
        flag_sigusr1 = 0;
    	flag_sigusr2 = 0;
    
        // block SIGUSR1
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGUSR1);
        if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)
    	{
            perror("sigprocmask error");
        }
    
        fprintf(stdout, "only catch sigusr2 can break, because sigusr1 has been blocked
    ");
        while(1)
    	{
            if(flag_sigusr1 || flag_sigusr2)
    		{
                fprintf(stdout, "break
    ");
                break;
            }
            sleep(5);
        }
    	fprintf(stdout, "second while was broken
    ");
    	
    	fprintf(stdout, "after second while was broken, flag_sigusr1=%d, flag_sigusr2=%d
    ", flag_sigusr1, flag_sigusr2);
    
        return 0;
    }
    

      

    多线程情况下每个线程共用信号处理函数,但是每个线程可以选择自己是否block某个信号。

    再看一个多线程的例子:子线程的功能同上,主线程接收到hup信号会向子线程发送usr2信号。

    #include<stdio.h>
    #include<signal.h>
    #include<unistd.h>
    #include<pthread.h>
    
    int flag_sigusr1 = 0;
    int flag_sigusr2 = 0;
    int flag_sighup  = 0;
    
    void sig_usr1(int signo)
    {
        fprintf(stdout, "sig|caught SIGUSR1
    ");
        flag_sigusr1 = 1;
        return;
    }
    
    void sig_usr2(int signo)
    {
        fprintf(stdout, "sig|caught SIGUSR2
    ");
        flag_sigusr2 = 1;
        return;
    }
    
    void sig_hup(int signo)
    {
        fprintf(stdout, "sig|caught SIGHUP
    ");
        flag_sighup = 1;
        return;
    }
    
    void *thread_control_signal(void *arg)
    {
        sigset_t newmask, oldmask;
        sigemptyset(&newmask);
    
        //thread block sighup
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGHUP);
        if(pthread_sigmask(SIG_BLOCK, &newmask, &oldmask) < 0)
    	{ 
            perror("sigprocmask error"); 
        } 
    
        fprintf(stdout, "thread|first while. catch sigusr1 or sigusr2 can break
    ");
        while(1)
    	{
            if(flag_sigusr1 || flag_sigusr2)
    		{
                fprintf(stdout, "thread|break
    ");
                break;
            }
            sleep(5);
        }
        flag_sigusr1 = 0;
    
        //thread block SIGUSR1
        sigaddset(&newmask, SIGUSR1);
        if(pthread_sigmask(SIG_BLOCK, &newmask, &oldmask) < 0)
    	{
            perror("sigprocmask error");
        }
    
        fprintf(stdout, "thread|first while. catch sigusr2 can break
    ");
        while(1)
    	{
            if(flag_sigusr1 || flag_sigusr2)
    		{
                fprintf(stdout, "break
    ");
                break;
            }
            sleep(10);
        }
        fprintf(stdout, "thread|thread exit
    ");
        return (void *)0;
    }
    
    int main()
    {
        sigset_t    newmask;
        pthread_t  tid;
        int        signo;
    
        //signal action
        signal(SIGUSR1, sig_usr1);
        signal(SIGUSR2, sig_usr2);
        signal(SIGHUP , sig_hup);
    
        if(pthread_create(&tid, NULL, thread_control_signal, NULL) < 0)
    	{
            perror("create pthread failed");
            return -1;
        }
    
        //main thread block sigusr1
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGUSR1);
        if(pthread_sigmask(SIG_BLOCK, &newmask, NULL) < 0)
    	{
            perror("sigprocmask error");
        }
    
        //main thread wait sighup
        sigemptyset(&newmask);
        sigaddset(&newmask, SIGHUP);
        if(sigwait(&newmask, &signo) < 0)
    	{
            perror("sigwait failed");
            return -1;
        }
        fprintf(stdout, "main|get SIGHUP
    ");
    
        pthread_kill(tid, SIGUSR2);
        pthread_kill(tid, SIGUSR2);
        pthread_join(tid, NULL);
    
        fprintf(stdout, "main|exit
    ");
        return 0;
    }
    

      

    kill函数向进程发送信号,pthread_kill用于向线程发送信号。

  • 相关阅读:
    js-快速选择日期区间
    关于状态更新时间字段取值的问题
    MySql 前缀索引
    Java springMVC 多数据源的实现和使用
    哈哈哈,终于找到一个安稳的“家”了
    POJ 1724: Roads
    POJ 1221: UNIMODAL PALINDROMIC DECOMPOSITIONS
    createjs 用户画线 粗细bug Graphics setStrokeStyle() 粗细BUG
    GAudio是一个音频播放SDK
    新做的一个基于OPENGL的gui库
  • 原文地址:https://www.cnblogs.com/kex1n/p/8296623.html
Copyright © 2020-2023  润新知