更改进程的信号屏蔽字可以阻塞所选择的信号,或解除对它们的阻塞。使用这种技术可以保护不希望由信号中断的代码临界区。如果希望对一个信号解除阻塞,然后pause等待以前被阻塞的信号发生,则又将如何呢?假定信号时SIGINT,实现这一点的一种不正确的方法是:

sigset_t    newmask, oldmask;

sigemptyset(&newmask);

sigaddset(&newmask, SIGINT);

/* block SIGINT and save current signal mask */if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

err_sys("SIG_BLOCK error");

/* critical region of code */if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

err_sys("SIG_SETMASK error");

/* window is open */

pause();    /* wait for signal to occur */

/* continue processing */

如果在信号阻塞时将其发送给进程,那么该信号的传递就被推迟直到对它解除了阻塞。对应用程序而言,该信号好像发生在解除对SIGINT的阻塞和pause之间。如果发生了这种情况,或者如果在解除阻塞时刻和pause之间确实发生了信号,那么就产生了问题。因为我们可能不会再见到该信号,所以从这种意义上而言,在此时间窗口(解除阻塞和pause之间)中发生的信号丢失了,这样就使pause永远阻塞。

为了纠正此问题,需要在一个原子操作中先恢复信号屏蔽字,然后使进程休眠。这种功能是由sigsuspend函数提供的。

#include <signal.h>

int sigsuspend( const sigset_t *sigmask );

返回值:-1,并将errno设置为EINTR

将进程的信号屏蔽字设置为由sigmask指向的值。在捕捉到一个信号或发生了一个会终止该进程的信号之前,该进程被挂起。如果捕捉到一个信号而且从该信号处理程序返回,则sigsuspend返回,并且将该进程的信号屏蔽字设置为调用sigsuspend之前的值。

#include <unistd.h>

#include <signal.h>

#include <stdio.h>

void handler(int sig)   //信号处理程序

{

if(sig == SIGINT)

printf("SIGINT sig");

else if(sig == SIGQUIT)

printf("SIGQUIT sig");

else

printf("SIGUSR1 sig");

}

int main()

{

sigset_t new,old,wait;   //三个信号集

struct sigaction act;

act.sa_handler = handler;

sigemptyset(&act.sa_mask);

act.sa_flags = 0;

sigaction(SIGINT, &act, 0);    //可以捕捉以下三个信号:SIGINT/SIGQUIT/SIGUSR1

sigaction(SIGQUIT, &act, 0);

sigaction(SIGUSR1, &act, 0);

sigemptyset(&new);

sigaddset(&new, SIGINT);  //SIGINT信号加入到new信号集中

sigemptyset(&wait);

sigaddset(&wait, SIGUSR1);  //SIGUSR1信号加入wait

sigprocmask(SIG_BLOCK, &new, &old);       //将SIGINT阻塞,保存当前信号集到old中

//临界区代码执行

if(sigsuspend(&wait) != -1)  //程序在此处挂起;用wait信号集替换new信号集。即:过来SIGUSR1信  号,阻塞掉,程序继续挂起;过来其他信号,例如SIGINT,则会唤醒程序。执行sigsuspend的原子操作。注意:如果“sigaddset(&wait, SIGUSR1);”这句没有,则此处不会阻塞任何信号,即过来任何信号均会唤醒程序。

printf("sigsuspend error");

printf("After sigsuspend");

sigprocmask(SIG_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_int(int signo){

if(signo == SIGINT){

printf("\n interrupt \n");

}

//当收到退出信号的时候,全局变量置为1

else if(signo == SIGQUIT){

quitflag == 1;

}

}

void suspend_function(){

sigset_t newmask,oldmask,zeromask;

//设置中断和退出的信号处理。

signal(SIGINT,sig_int);

signal(SIGQUIT,sig_int);

sigemptyset(&zeromask);

sigemptyset(&newmask);

sigaddset(&newmask,SIGQUIT);

sigprocmask(SIG_BLOCK,&newmask,&oldmask);

while(quitflag == 0)

sigsuspend(&zeromask);

quitflag=1;

sigprocmask(SIG_SETMASK,&oldmask,NULL);

exit(0);

}

程序结果如下:

linux c编程:信号(五) sigsuspend的更多相关文章

  1. linux系统编程--信号

    信号的概念 man 7 siganl  查看man手册 信号在我们的生活中随处可见, 如:古代战争中摔杯为号:现代战争中的信号弹:体育比赛中使用的信号枪......他们都有共性:1. 简单 2. 不能 ...

  2. Linux系统编程——信号

    目录 信号的介绍 信号的机制 信号的编号 Linux常规信号一览表 信号的产生 终端按键产生信号 硬件异常产生信号 kill函数/命令产生信号 信号的操作函数 信号集设定 sigprocmask函数 ...

  3. Linux网络编程学习(五) ----- 信号(第四章)

    1.基本概念 进程阻塞: 进程执行条件得不到满足,就自动放弃CPU资源而进入休眠状态,以等待条件满足,当条件满足时,系统就将控制权还给该进程进行未完成的操作 共享资源: 进程间协调使用的系统资源 锁定 ...

  4. Linux系统编程—信号集操作函数

    先来回顾一下未决信号集是怎么回事. 信号从产生到抵达目的地,叫作信号递达.而信号从产生到递达的中间状态,叫作信号的未决状态.产生未决状态的原因有可能是信号受到阻塞了,也就是信号屏蔽字(或称阻塞信号集, ...

  5. Linux系统编程—信号捕捉

    前面我们学习了信号产生的几种方式,而对于信号的处理有如下几种方式: 默认处理方式: 忽略: 捕捉. 信号的捕捉,说白了就是抓到一个信号后,执行我们指定的函数,或者执行我们指定的动作.下面详细介绍两个信 ...

  6. linux系统编程之信号(七)

    今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...

  7. Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号

    Linux 系统编程 学习:03-进程间通信1:Unix IPC(2)信号 背景 上一讲我们介绍了Unix IPC中的2种管道. 回顾一下上一讲的介绍,IPC的方式通常有: Unix IPC包括:管道 ...

  8. Linux网络编程(五)

    /*Linux网络编程(五)——多路IO复用之select() 网络编程中,使用IO复用的典型场合: 1.当客户处理多个描述字时(交互式输入以及网络接口),必须使用IO复用. 2.一个客户同时处理多个 ...

  9. Linux高性能server编程——信号及应用

     信号 信号是由用户.系统或者进程发送给目标进程的信息.以通知目标进程某个状态的改变或系统异常. Linux信号可由例如以下条件产生: 对于前台进程.用户能够通过输入特殊的终端字符来给它发送信号. ...

随机推荐

  1. EffectiveJava(19)导出常量的几种方式 - - 接口只用于定义类型

    package com.classinteface.finalinterface; /** * 常量接口模式 java.io.ObjectStreamConstants * 这种模式会导致实现其的类将 ...

  2. Node.js 网页瘸腿爬虫初体验

    延续上一篇,想把自己博客的文档标题利用Node.js的request全提取出来,于是有了下面的初哥爬虫,水平有限,这只爬虫目前还有点瘸腿,请看官你指正了. // 内置http模块,提供了http服务器 ...

  3. #淘宝#复制分享宝贝内容,打开淘宝APP,自己主动弹出宝贝提示信息

    场景描写叙述: 淘宝复制连接,分享出去,比方拷贝到QQ好友.微信好友,一个宝贝信息.然后你朋友长按复制你分享它了的这个宝贝.当然打开手机淘宝时.自己主动会跳出宝贝的信息,点击确定能够直接进入宝贝详情 ...

  4. python raise assert

    class MyException(Exception): def __init__(self,error_msg): self.error_msg=error_msg def __str__(sel ...

  5. ionic开发之优化目录结构

    当我们来个ionic start circleApp tabs的时候,会自动生成目录结构,基本如下: 显然这不利于项目的管理,当你的项目越来越复杂的时候,这是不够的.我们必须要按照模块进行文件夹的方式 ...

  6. 标准库Stack的一种实现

    本文实现了STL中stack的大部分功能,同时添加了一些功能. 注意以下几点: 1.Stack是一种适配器,底层以vector.list.deque等实现 2.Stack不含有迭代器 在本例中,我添加 ...

  7. Ajax系列之中的一个:ajax旧貌换新颜

    什么是ajax? 什么是Ajax? Ajax就是Asynchronous +JavaScript+XML.中文翻译为:异步的javascript与XML,它是利用javascript语言和xml数据实 ...

  8. (七)Thymeleaf的 th:* 属性之—— th: ->设值& 遍历迭代& 条件判断

    3.4 属性值的设置 3.4.1 使用th:attr来设置属性的值 <form action="subscribe.html" th:attr="action=@{ ...

  9. mysql学习笔记(编辑中)

    1.LAST_INSERT_ID()依赖于当前服务器会话中自动产生的序列编号.同时括号中也可以赋值更新数据,eg: update test set id = last_insert_id(id+10) ...

  10. Atitit.程序包装exe启动器 打包 发布 设计 -生成exe java

    Atitit.程序包装exe启动器 打包 发布 设计 -生成exe java 1. 要实现的功能1 2. ahk是个好东东..能启动了...1 3. exe4j   vs  nativej1 4. 2 ...