Linux信号透彻分析理解与各种实例讲解( 六 )


int pause(void);
int sigsuspend(const sigset_t *sigmask);
pause函数挂起一个进程 , 直到一个信号发生 。
sigsuspend函数的执行过程如下:
(1)设置新的mask去阻塞当前进程
(2)收到信号 , 调用信号的处理函数
(3)将mask设置为原先的掩码
(4)sigsuspend函数返回
可以看出 , sigsuspend函数是等待一个信号发生 , 当等待的信号发生时 , 执行完信号处理函数后就会返回 。 它是一个原子操作 。
保护临界区的中断:
(1)首先用sigprocmask去阻塞信号
(2)执行后关键代码后,用sigsuspend去捕获信号
(3)然后sigprocmask去除阻塞
这样信号就不会丢失了 , 而且不会中断临界区 。
使用pause函数对临界区的保护:
Linux信号透彻分析理解与各种实例讲解文章插图
上面的程序是用pause去保护临界区 , 首先用sigprocmask去阻塞SIGINT信号 , 执行临界区代码 , 然后解除阻塞 。 最后调用pause()函数等待信号的发生 。 但此时会产生一个问题 , 如果信号在解除阻塞与pause之间发生的话 , 信号就可能丢失 。 这将是一个不可靠的信号机制 。
因此 , 采用sigsuspend可以避免上述情况发生 。
使用sigsuspend对临界区的保护:
Linux信号透彻分析理解与各种实例讲解文章插图
使用sigsuspend对临界区的保护就不会产生上述问题了 。
3. sigsuspend函数的用法
sigsuspend函数是等待的信号发生时才会返回 。
sigsuspend函数遇到结束时不会返回 , 这一点很重要 。
示例:
下面的例子能够处理信号SIGUSR1,SIGUSR2,SIGSEGV,其它的信号被屏蔽 , 该程序输出对应的信号 , 然后继续等待其它信号的出现 。
#include#includevoid signal_set1(int);//信号处理函数 , 只传递一个参数信号代码void signal_set(struct sigaction *act){switch(act->sa_flags){case (int)SIG_DFL:printf("using default hander/n");break;case (int)SIG_IGN:printf("ignore the signal/n");break;default:printf("%0x/n",act->sa_handler);}}void signal_set1(int x){//信号处理函数printf("xxxxx/n");while(1){}}int main(int argc,char** argv){int i;struct sigaction act,oldact;act.sa_handler = signal_set1;act.sa_flags = SA_RESETHAND;//SA_RESETHANDD 在处理完信号之后 , 将信号恢复成默认处理//SA_NODEFER在信号处理程序执行期间仍然可以接收信号sigaction (SIGINT,//改变信号的处理模式for (i=1; i<12; i++){printf("signal %d handler is : ",i);sigaction (i,NULL,signal_set(//如果act为NULL , oldact会存储信号当前的行为//act不为空 , oldact不为空 , 则oldact会存储信号以前的处理模式}while(1){//等待信号的到来}return 0;}程序运行结果:
received sigusr1 signal
received sigusr2 signal
received sigsegv signal
received sigusr1 signal
已终止
另一个终端用于发送信号:
先得到当前进程的pid, ps aux|grep 程序名
kill -SIGUSR1 4901
kill -SIGUSR2 4901
kill -SIGSEGV 4901
kill -SIGTERM 4901
kill -SIGUSR1 4901
解释:
第一行发送SIGUSR1 , 则调用信号处理函数 , 打印出结果 。
第二 , 第三行分别打印对应的结果 。
第四行发送一个默认处理为终止进程的信号 。
但此时 , 但不会终止程序 , 由于sigsuspend遇到终止进程信号并不会返回 , 此时并不会打印出"已终止" , 这个信号被阻塞了 。 当再次发送SIGURS1信号时 , 进程的信号阻塞恢复成默认的值 , 因此 , 此时将会解除阻塞SIGTERM信号 , 所以进程被终止 。