通过更改进程的信号掩码,可以阻止或取消阻止选定的信号。 使用该技术,可以保护不想被信号中断的代码边界区域。 如果用一个信号解除阻止,然后pause等待以前被阻止的信号发生,怎么办? 假设信号时SIGINT,实现这一点的不正确方法之一如下。
sigset_tnewmask,oldmask;
sigemptyset 新掩码;
sigaddset 新掩码,SIGINT );
/* blocksigintandsavecurrentsignalmask */if sigprocmask SIG _ block,newmask,oldmask )0) ) )。
ERR_sysSIG_blockerror );
/* criticalregionofcode */if sigprocmask SIG _ setmask,oldmask,NULL )0) ) ) )。
ERR_sysSIG_setmaskerror );
/*窗口is open * /
pause ; /*waitforsignaltooccur*/
/*连续处理* /
如果在信号被阻止时发送到进程,则信号的传递将推迟,直到阻止被解除。 对于APP应用程序来说,此信号似乎发生在取消阻止SIGINT和pause之间。 如果发生这种情况,或者解除阻止的时间点与pause之间确实发生了信号,就会发生问题。 因为我们可能看不到这个信号,所以从这个意义上说,在这个时间窗口解除阻止和pause之间)发生的信号将会丢失,pause将永远被阻止。
要解决这个问题,必须用一个原子操作恢复信号屏蔽字,然后使过程休眠。 此功能由sigsuspend函数提供。
#includesignal.h
int sigsuspend 常数符号_ t *符号);
返回值:-1,将错误设置为EINTR
将进程的信号掩码设置为sigmask指向的值。 该进程挂起,直到收到捕获信号或终止该进程的信号。 如果捕获到信号并从信号处理程序返回,则返回sigsuspend,并将进程的信号掩码设置为调用sigsuspend之前的值。
#includeunistd.h
#includesignal.h
#includestdio.h
语音处理程序intsig )//信号处理程序
{
ifSIG==sigint ) ) ) )。
打印sigint SIG );
ELSEifSIG==SIGquit ) ) )。
打印机sigquitsig );
else
打印机SIG usr1SIG );
}
intmain ) )
{
sigset_tnew,old,wait; //三个信号集
structsigactionact;
act.sa_handler=handler;
sigemptysetact.sa_mask;
act.sa_flags=0;
sigactionsigint,act,0 ); 可以捕捉到SIGINT/SIGQUIT/SIGUSR1这3个信号
sigactionSIGquit,
&act, 0);
sigactionSIGUSR1, &act, 0);
sigemptyset&new);
sigaddset&new, SIGINT); //SIGINT信号加入到new信号集中
sigemptyset&wait);
sigaddset&wait, SIGUSR1); //SIGUSR1信号加入wait
sigprocmaskSIG_BLOCK, &new, &old); //将SIGINT阻塞,保存当前信号集到old中
//临界区代码执行
ifsigsuspend&wait) != -1) //程序在此处挂起;用wait信号集替换new信号集。即:过来SIGUSR1信 号,阻塞掉,程序继续挂起;过来其他信号,例如SIGINT,则会唤醒程序。执行sigsuspend的原子操作。注意:如果“sigaddset&wait, SIGUSR1);”这句没有,则此处不会阻塞任何信号,即过来任何信号均会唤醒程序。
printf”sigsuspend error”);
printf”After sigsuspend”);
sigprocmaskSIG_SETMASK, &old, NULL);
return 0;
}
sigsuspend的原子操作是:
(1)设置新的mask阻塞当前进程上面是用wait替换new,即阻塞SIGUSR1信号)
(2)收到SIGUSR1信号,阻塞,程序继续挂起;收到其他信号,恢复原先的mask即包含SIGINT信号的)。
(3)调用该进程设置的信号处理函数程序中如果先来SIGUSR1信号,然后过来SIGINT信号,则信号处理函数会调用两次,打印不同的内容。第一次打印SIGINT,第二次打印SIGUSR1,因为SIGUSR1是前面阻塞的)
(4)待信号处理函数返回,sigsuspend返回了。sigsuspend将捕捉信号和信号处理函数集成到一起了)
sigsuspend的另一种应用是等待一个信号处理程序设置一个全局变量,下面的这个程序用于捕捉中断信号和退出信号。但是只是希望在捕捉到退出信号的时候,才唤醒主例程
int quitflag;
void sig_intint signo){
ifsigno == SIGINT){
printf”\n interrupt \n”);
}
//当收到退出信号的时候,全局变量置为1
else ifsigno == SIGQUIT){
quitflag == 1;
}
}
void suspend_function){
sigset_t newmask,oldmask,zeromask;
//设置中断和退出的信号处理。
signalSIGINT,sig_int);
signalSIGQUIT,sig_int);
sigemptyset&zeromask);
sigemptyset&newmask);
sigaddset&newmask,SIGQUIT);
sigprocmaskSIG_BLOCK,&newmask,&oldmask);
whilequitflag == 0)
sigsuspend&zeromask);
quitflag=1;
sigprocmaskSIG_SETMASK,&oldmask,NULL);
exit0);
}
程序结果如下:
转载于:https://www.cnblogs.com/zhanghongfeng/p/9153060.html