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用於向執行緒傳送訊號。