zoukankan      html  css  js  c++  java
  • 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用于向线程发送信号。

  • 相关阅读:
    .NET: 如何在宿主中动态加载所有的服务
    SharePoint : 自定义权限设置中可能遇到的问题
    在javascript中进行cookie的读写操作
    .NET : 如何读取数据库中的bmp图片数据
    Microsoft Security Essential
    利用ashx和ajax实现表格的异步填充
    IPV6
    Windows 7 : 开发人员资源
    SQL Server : 使用SQL Express的User Instance特性
    .NET : 如何在Windows Forms中使用DataRepeater控件
  • 原文地址:https://www.cnblogs.com/kex1n/p/8296623.html
Copyright © 2011-2022 走看看