// - pending signal
程序中存在关键代码区。当程序处于关键代码区运行时,程序员希望不被收到信号中断关键代码区的执行。
同时又不允许简单忽略到达的信号,而是待关键代码区执行结束后,再处理接收到的信号。 - sigprocmask 来设置阻止传递的信号
// - 信号的挂起概念
当信号产生的时候 ,内核会在接收到信号的进程的PCB中设置相关的标志,以表明该进程接收到了信号。之后,该信号对应的信号处理程序
会被执行,这个执行操作被称之为传递信号。 从信号的产生到信号传递 ,这期间信号所处的状态称为挂起状态(pendding)
可以设置选项,以使进程阻塞某个(或某些)特定信号的传递 。 如果进程接收到被阻塞传递的信号,该信号将会一直处于挂起状态,直到进程解除了
对该信号的阻塞,该信号才能被传递。 每一个进程都有一个信号的掩码,该掩码用来定义被阻塞传递的信号集合。
// - 相关api
头文件:#include <signal.h>
//1.函数原型:int sigemptyset(sigset_t *set);
功能:清空信号集合*set ,即初始化信号集合*set中的每位置为0
参数:
set - 信号集合set
返回值:
成功 返回0
失败或错误 返回-1
//2.函数原型:int sigfillset(sigset_t *set);
功能:initializes set to full, including all signals. 即将信号集合*set 中的每一位都置为1
参数:
set - 信号集合set
返回值:
成功: 返回0
失败或错误 返回 -1
//3.函数原型:int sigaddset(sigset_t *set , int signum);
功能:将信号集合*set中对应于信号signum的位置置1
参数:
set - 信号集合set
signum - 信号位置
返回值:
成功 返回 0
失败 返回-1
//4.函数原型: int sigdelset(sigset_t *set , int signum);
功能:将信号集合*set中对应于信号signum的位置置0
参数:
set - 信号集合set
signum - 信号位置
返回值: 成功返回 0 , 失败返回 -1
//5.函数原型: int sigpending(sigset_t *set);
功能:将正在被阻塞递送的信号记录到*set中
returns the set of signals that are pending for delivery
to the calling thread (i.e., the signals which have been raised while
blocked). The mask of pending signals is returned in set.
参数:
set - 信号集合
返回值 成功返回0 失败返回-1
//6.函数原型:int sigismember(const sigset_t *set, int signum);
功能:若信号集合*set中对应于信号signum的位为1 ,返回真。失败返回假
returns 1 if signum is a member of set, 0 if signum is
not a member, and -1 on error.
参数:
set - 信号集合
signum - 信号位置
返回值:
成功返回 1 失败返回 0
//7.函数原型: int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
功能:此函数用来获取和改变调用进程的信号掩码。根据参数how可以分以下几种:SIG_BLOCK、SIG_UNBLOCK、SIG_SETMASK
It is used to change the signal mask, the set of currently blocked signals. The behaviour of the call is dependent on the value
of how, as follows.
参数:
how - 信号操作类型
// - SIG_BLOCK 信号集合掩码被设置为当前的信号集合与*set的并集
// - sigset_t newmask = 0x4 ,oldmask;
// - sigprocmask(SIG_BLOCK , newmask,oldmask);
// - 解析: 假设进程的当前信号集合掩码为0x3(即会阻塞0号跟1号信号的递送),在执行上述的代码后,进程的当前信号集合掩码
会变成0x7(即进程会阻塞 0 ,1,2号信号递送),而oldmask将等于0x3(旧的信号集合掩码)
// - SIG_UNBLOCK 信号集合掩码被设置为当前的信号集合减去*set中的信号
// - sigset_t newmask = 0x1 ,oldmask;
// - sigprocmask(SIG_UNBLOCK , newmask ,oldmask);
// - 解析:假设进程的当前信号集合掩码为0x3(即:进程会阻塞0 ,1 号信号递送),在执行上述的代码后,进程的当前信号集合
掩码会变为0x2(即进程会阻塞1号信号的递送),而oldmask将等于0x3(进程的旧的信号集合掩码)
// - SIG_SETMASK 信号集合掩码被设置为*set
// - sigset_t newmask = 0x4 , oldmask;
// - sigprocmask(SIG_SETMASK , &newmask ,&oldmask);
// - 解析:假设进程的当前信号集合掩码为0x3,执行上述代码 后,进程的当前信号集合掩码会变成0x4,而oldmask将等于0x3(进程的旧信号
集合掩码)。
set - 信的信号集合
oldset - 旧的信号集合
返回值: 成功 返回 0 , 失败或错误返回 -1
eg:
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static void sig_int(int);
int main(int argc ,char *argv[]){
struct sigaction act;
sigset_t newmask ,oldmask ,pendmask;
if(signal(SIGQUIT , sig_int) == SIG_ERR){
printf("can't catch SIGQUIT");
exit(1);
}
if(signal(SIGINT , sig_int) == SIG_ERR){
printf("can't catch SIGINT");
exit(2);
}
sigemptyset(&newmask);
sigaddset(&act.sa_mask , SIGQUIT);
// Enter Critical Area , block SIGQUIT and save current signal mask
if(sigprocmask(SIG_BLOCK , &newmask , &oldmask) < 0){
printf("SIG_BLOCK ERROR");
exit(4);
}
sleep(15); // Crtical Area Code here , and SIGQUIT will remain pending
if(sigpending(&pendmask) < 0){
printf("sigpending error");
exit(5);
}
if(sigismember(&pendmask , SIGQUIT)){
printf("\nSIGQUIT pending \n");
}
// Exit Critical Area , reset signal mask which unblocks SIGUIT
if(sigprocmask(SIG_SETMASK , &oldmask , NULL) < 0){
printf("SIG_SETMASK error");
exit(6);
}
printf("SIGQUIT unblocked \n");
sleep(100);
return 0;
}
static void sig_int(int signo){ // argument is signal number
int i ;
if(signo == SIGINT){
printf("received SIGINT \n");
for(i = 1000000000 ; i > 0 ; i--)
;
printf("processed SIGINT \n");
}else if(signo == SIGQUIT){
printf("caught SIGQUIT\n");
}else{
printf("received signal %d \n" , signo);
}
return ;
}