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\n");
    flag_sigusr1 = 1;
    return;
}

void sig_usr2(int signo)
{
    fprintf(stdout, "caught SIGUSR2\n");
    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\n");
	
    while(1)
	{
        if(flag_sigusr1)
		{
            fprintf(stdout, "break\n");
            break;
        }
        sleep(5);
    }
	fprintf(stdout, "first while was broken\n");
	
	//重新設置為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\n");
    while(1)
	{
        if(flag_sigusr1 || flag_sigusr2)
		{
            fprintf(stdout, "break\n");
            break;
        }
        sleep(5);
    }
	fprintf(stdout, "second while was broken\n");
	
	fprintf(stdout, "after second while was broken, flag_sigusr1=%d, flag_sigusr2=%d\n", 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\n");
    flag_sigusr1 = 1;
    return;
}

void sig_usr2(int signo)
{
    fprintf(stdout, "sig|caught SIGUSR2\n");
    flag_sigusr2 = 1;
    return;
}

void sig_hup(int signo)
{
    fprintf(stdout, "sig|caught SIGHUP\n");
    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\n");
    while(1)
	{
        if(flag_sigusr1 || flag_sigusr2)
		{
            fprintf(stdout, "thread|break\n");
            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\n");
    while(1)
	{
        if(flag_sigusr1 || flag_sigusr2)
		{
            fprintf(stdout, "break\n");
            break;
        }
        sleep(10);
    }
    fprintf(stdout, "thread|thread exit\n");
    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\n");

    pthread_kill(tid, SIGUSR2);
    pthread_kill(tid, SIGUSR2);
    pthread_join(tid, NULL);

    fprintf(stdout, "main|exit\n");
    return 0;
}

  

kill函數向進程發送信號,pthread_kill用於向線程發送信號。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM