信号的“未决”是一种状态,指的是从信号的产生到信号被处理前的这一段时间;
信号的“阻塞”是一个开关动作,指的是阻止信号被处理,但不是阻止信 号产生。

信号的阻塞就是让系统暂时保留信号留待以后发送。由于另外有办法让系统忽略信号,所以一般情况下信号的阻塞只是暂时的,只是为了 防止信号打断敏感的操作。
* 当你需要修改某些全局变量时,你可以通过sigprocmask()函数阻塞处理函数中也使用该变量的信号。
* 在某些信号处理函数中,为了阻止同类信号的到来,可以使用sigaction()函数的sa_mask阻塞特定的信号。
11.7.1 阻塞信号的作用
使用函数sigprocmask()阻塞信号的传递,只是延迟信号的到达。信号会在解除阻塞后继续传递。这种情况往往需要在信 号程序和其它程序共享全局变量时,如果全局变量的类型不是sig_atomic_t类型,当一部分程序恰好读、写到变量的一半发生信号,而信号程序里会改 变该信号,那么就会产生混乱。为了避免这种混乱,提供程序的可靠性,你必须在操作这类变量前阻塞信号,操作完成后恢复信号的传递。
信号阻塞也 用来处理必须保证连续操作的完整性方面。比如,你需要检测一个标志(可以是sig_atomic_t类型),该标志在信号程序中设置,当标志没有设置时可 以执行某个操作。假如恰好在检测标志后发生信号,那么信号返回后,程序也会执行这个操作,即使已经设置了标志。这显然会引起程序的不稳定。最好的方法就是 在检测标志到执行操作之间阻塞信号的发生。
11.7.2 信号集
所有的信号阻塞函数都使用称作信号集的数据结构来表明受到影响的信号。每一个操作都包括两个阶段:创建信号集,传递信号集给特定的库函数。下面说明信号集 和相关的数据类型:
sigset_t:这个数据类型用来代表信号的集合,有两种方法对它进行初始化。一种是通过函数 sigemptyset()使之不包含任何信号,然后用sigaddset()函数加入需要的信号。另一种方法是通过函数sigfillset()使之包 含所以信号,然后通过sigdelset()函数删除我们不需要的信号。注意,千万不用试图通过手工方式直接操作这种类型变量,否则会带来严重的错误。下 面介绍相关的函数。
int sigemptyset(sigset_t *set):初始化信号集set使之不包含任何信号,这个函数总是返回0。
int sigfillset(sigset_t *set):初始化信号集set使之包含所有的信号,这个函数也是总返回0。
int sigaddset(sigset_t *set, intsignum):该函数把信号signum加入到信号集set中,需要注意的是这个函数只是修改了set变量本身,并不作其它操作。该函数成功操作 返回0,失败返回-1,错误代码设置成EINVAL,表示signum不是有效的信号代码。
int sigdelset(sigset_t *set, int signum):该函数从信号集set中删除信号signum,其它方面和sigaddset()函数类似,不再赘述。
int sigismember(const sigset_t *set,intsignum):这个函数测试信号signum是否包含在信号集合set中,如果包含返回1,不包含返回0,出错返回-1。错误代码也只 有一个EINVAL,表示signum不是有效的信号代码。
11.7.3 进程的信号掩码
我们称正在阻塞的信号的集合为信号掩码(signal mask)。每个进程都有自己的信号掩码,创建子进程时子进程将继承父进程的信号掩码。我们可以通过修改当前的信号掩码来改变信号的阻塞情况。
int sigprocmask(int how, const sigset_t *set,sigset_t *oldset),该函数用来检查和改变调用进程的信号掩码,其中的how参数指出信号掩码改变的方式,必须是下面的值之一:
SIG_BLOCK,阻塞set中包含的信号。意思是说把set中的信号加到当前的信号掩码中去,新的信号掩码是set和旧信号掩码的并集。
SIG_UNBLOCK,解除set中信号的阻塞,从当前信号掩码中去除set中的信号。
SIG_SETMASK,设置信号掩码,既按照set中的信号重新设置信号掩码。
最后一个参数是进程原来的信号集。如果你只需要改变信号的阻塞情况而不需要关心原来的值,可以传递NULL指针给函数。如果你希望什么也不改变,只是想获 得当前信号掩码的信息,那么把set设置成NULL,old中返回当前的设置。
sigprocmask()函数成功返回0,失败返回-1。失败时错误代码只可能是EINVAL,表示参数how不合法。
不能阻塞 SIGKILL和SIGSTOP等信号,但是当set参数包含这些信号时sigprocmask()不返回错误,只是忽略它们。另外,阻塞SIGFPE这 样的信号可能导致不可挽回的结果,因为这些信号是由程序错误产生的,忽略它们只能导致程序无法执行而被终止。
11.7.4 举例:禁止关键代码时信号到达
假定你建立信号SIGALRM的处理函数,在其中设置一个标志。主程序中检查标志并清除,使用函数sigprocmask()控制信号到达:
#include
volatile sig_atomic_t flag=0;

int
main(void)
{
sigset_t block_alarm;
... ...
sigemptyset(&block_alarm);
sigaddset(&block_alarm,SIGALRM);
while(1)
{
sigprocmask(SIG_BLOCK,&block_alarm,NULL);
if(flag)
{
... ...
flag=0;
}
sigprocmask(SIG_UNBLOCK,&block_alarm,NULL);
... ...
}
}
11.7.5 在信号句柄中阻塞信号
信号句柄执行时,如果你希望从头至尾不会被其它信号打扰,那么你必须阻塞其它信号。当一个信号句柄激活时,相同的信号自动被阻塞,但是其它信号并不会阻 塞,最可靠的方法是使用sigaction结构的sa_mask成员。例如:
#include
#include

void catch_stop();

void
install_handler(void)
{
struct sigaction setup_action;
sigset_t block_mask;
sigemptyset(&block_mask);
sigaddset(&block_mask,SIGINT);
sigaddset(&block_mask,SIGQUIT);
setup_action.sa_handler=catch_stop;
setup_action.sa_mask=block_mask;
setup_action.sa_flag=0;
sigaction(SIGINT,&setup_action,NULL);
}
这个方法比在信号函数中使用 sigprocmask()函数可靠,因为使用sigprocmask()函数起码无法避免在信号函数开始的信号不被阻塞的间隙。使用这个机制你不能从当 前信号掩码中删除信号,但是,在信号函数当中,你可以使用sigprocmask()阻塞信号。在任何情况下,信号句柄返回时,系统重新装入进入信号句柄 之前的信号掩码。当信号句柄一返回,信号句柄执行时被阻塞的信号就会立即到达,甚至在返回被中断的代码前就要进入新的信号处理句柄。
11.7.6 查找阻塞的信号
你能够使用函数sigpending()来查找系统中何种信号有正在被阻塞的信号。
int sigpending(sigset_t *set),该函数把存在阻塞信号的信号类型放置到set中,可以使用sigismenber()函数判断某种信号是否是set的成员。该函数成功返回 0,失败返回-1。
下面举例说明:
#include
#include

sigset_t base_mask,wait_mask;

sigemptyset(&base_mask);
sigaddset(&base_mask,SIGINT);
sigaddset(&base_mask,SIGTSTP);
sigprocmask(SIG_SETMASK,&base_mask,NULL);
... ...
sigpending(&waiting_mask);
if(sigismember(&waiting_mask,SIGINT))
{
//do something, if user try killing the process
}
else if(sigismember(&waiting_mask,SIGTSTP))
{
//user tring to stop process
}
对于同一种信号,如果有被阻塞的信号存在,那么其它到来的信号就会被丢弃,而不是被阻塞。
11.7.7 信号阻塞的代替方法
我们可以采用在信号处理程序中读取其它程序进入关键代码前设置的标志来判断是否进行处理,如果不能进行处理,则在一个公共变量中设置不能进行处理的信号的 值,关键代码执行完成后再重新发送该信号,请看下面的例子:
volatile sig_atomic_t signal_pending;
volatile sig_atomic_t defer_signal;

void
handler(int signum)
{
if(defer_signal)
signal_pending=signum;
else
...
}

...
void
update_number(int frob)
{
defer_signal++;
...
defer_signal--;
if(defer_signal==0&&signal_pending!=0)
raise(signal_pending);
}

信号是unix处理异步事件的经典方法。产生信号的方法一般有:
        用户按中断键、硬件异常信号、软件异常信号、用户的kill命令等。系统也可以有多种方式处理这些异步 事件,比如:忽略信号、捕捉信号或者执行默认动作。
        大多数unix程序都是用信core文件来检查进程终止时候的状态的。 core文件就是对于该文件的进程存储映像进行复制。

一定要记住这两种情况:
   1)当进程启动的时候,所有信号的状态就是系统默认或者忽略。除非调用exec动作。
     因为exec动作,将原先设置为要捕捉的信号为默认动作,道理很简单,就是exec要用新的进程地址空间覆盖旧的,自然原先的信号就已经被屏蔽了。
   2)开启一个子进程的时候,子进程继承父进程的信号处理方式。因为子进程一开始启动就复制了父进程的存储映像,信号捕捉函数地址在父子进程中都是有意义 的。

signal的信号处理方式带有好多的缺陷,比如,在产生信号和调用signal信号处理程序之间有一个时 间窗口,如果再来一个信号可能丢失。等等。

在执行慢速的系统调用的时候,进程很可能阻塞几个小时或者数天,如果进程在执行一个低速系统调用期间捕捉到 一个信号的时候,那么该系统调用就被中断不在继续执行。因为一个信号发生了,这就意味着发生了某种事情,所以这是唤醒被阻塞的进程的好机会。
   为了帮助应用进程不必处理被总段的系统调用,linux系统引入了某些被中断系统调用的自动重启函 数,包括:Ioctl,read,readv,write,writev,wait和waitpid。前5个只对低速设备调用才有效,而后两个只对捕捉到 进程退出信号时才有效。可重入函数主要用于多任务环境中,一个函数是可重入与否,简单的说就是否可以被中断。假如一个链表,如果被中断则会发生莫名的错误,其执行序列是不可预测的。
    信号发生的时候到递送之间的时间间隔,我们称为信号时未决的。在未决的信号期间,如果我们阻塞了某些信号,那么,即使我们产生信号,这些都会被阻塞。除非 等解除阻塞以后,系统才会处理这些信号。而且,阻塞期间多次产生的同一个信号,解除阻塞后,系统处理且只处理一次。

引用原文:
1. http://www.hadoopor.com/redirect.php?tid=1156&goto=lastpost
2. http://www.groad.net/bbs/read.php?tid-920.html

linux 信号阻塞和信号未决相关推荐

  1. Linux 信号详解五(信号阻塞,信号未决)

    信号在内核中的表示 执行信号的处理动作成为信号递达(Delivery),信号从产生到递达之间的状态称为信号未决(Pending).进程可以选择阻塞(Block)某个信号. 被阻塞的信号产生时将保持在未 ...

  2. 【Linux系统编程】信号 (下)

    00. 目录 文章目录 00. 目录 01. 信号集 02. 信号阻塞集 03. sigaction函数 04. 附录 01. 信号集 为了方便对多个信号进行处理,一个用户进程常常需要对多个信号做出处 ...

  3. 可靠信号与不可靠信号

    来自:http://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html 一.信号及信号来源 信号本质 信号是软件中断,是在软件层次上 ...

  4. 【B站视频笔记】linux 进程间通信(ipc)信号(软中断信号)signal库函数、可靠信号和不可靠信号、信号集sigprocmask(信号掩码、信号递达Delivery、信号未决Pending)

    [视频教程]Linux信号详解(可靠信号.不可靠信号.阻塞信号.信号处理函数) [博文]Linux信号 文章目录 背景 课程笔记 一.如何让程序在后台运行 1.加"&"符号 ...

  5. 信号集操作函数,信号阻塞与未决

    一,信号集及相关操作函数 信号集被定义为一种数据类型: typedef struct { unsigned long sig[_NSIG_WORDS]: } sigset_t 信号集用来描述信号的集合 ...

  6. linux下的进程信号,信号注册、处理方式、注销,信号阻塞及volatile代码优化

    信号量与信号的区别! 信号量:内核中的一个计数器/实现进程间同步(条件判断合理性)与互斥(同一时间唯一访问安全性). 信号:进程之间事件异步通知的一种方式,是一种软中断,非信号量. 作用:操作系统通过 ...

  7. Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存

    Linux进程间通信--进程,信号,管道,消息队列,信号量,共享内存 参考:<linux编程从入门到精通>,<Linux C程序设计大全>,<unix环境高级编程> ...

  8. linux 程序收到sigsegv信号_信号

    当其他方式不起作用时(例如标准输入被冻结),信号是提供低优先级信息和用户与其程序交互的便捷方式.它们允许程序在事件发生时清理或执行操作.有时,程序可以选择忽略受支持的事件.由于处理信号的方式,制作一个 ...

  9. Linux系统编程----7(信号集,信号屏蔽,信号捕捉)

    信号集操作函数 内核通过读取未决信号集来判断信号是否应被处理.信号屏蔽字 mask 可以影响未决信号集.而我们可以在应 用程序中自定义 set 来改变 mask.已达到屏蔽指定信号的目的. 信号集设定 ...

  10. Day53 Linux setitimer函数 信号集操作函数 信号捕捉 SIGCHLD信号

    目录 setitimer函数 信号集操作函数 1.信号集设定 2.igprocmask函数 3.sigpending函数 信号捕捉 1.signal函数 2.sigaction函数 SIGCHLD信号 ...

最新文章

  1. 21天搞定Python爬虫
  2. 解决pip install keras报错问题
  3. 老鸟谈画图能力对运维人员的重要性
  4. hdu hide handkerchief
  5. arduino 勘智k210_如何评价嘉楠耘智的勘智K210芯片?
  6. JWT令牌的秘密轮换
  7. nuxt.js 引入第三方插件报window is not defined
  8. Chrome Frame
  9. 计算机桌面组成部分教案,三年级信息技术第五课设置个性桌面教学设计
  10. logback的日志文件中出现大量的ESC符号
  11. WIN7使用各种激活软件都不管用的解决办法
  12. linux如何生成awr报告,手工生成AWR报告方法记录
  13. 微信小程序中长按识别二维码
  14. 测试工程师/测试开发面试题整理
  15. 普天视PTS-3130C 模拟网络AHD监控 三维云台键盘 PELCO解析程序
  16. 弘辽科技:拼多多DSR动态评分有多么的重要
  17. ASCII 编码对照表 一览表
  18. word表格导出为图像
  19. 2C4T与4C4T在计算密集型任务下的效率对比
  20. shell的循环运用

热门文章

  1. 查看最大的10个文件
  2. 网页素材精品:一组五彩缤纷的免费矢量背景素材
  3. uva 11234 Expressions
  4. 利用oracle long类型字段,插入大文本
  5. Webstorm 2021 开启内存显示设置
  6. JavaScript —— Symbol数据类型之不延伸
  7. linux有线程的概念,Linux线程相关概念
  8. 中班音乐活动 机器人_幼儿园大班音乐活动教案:《机器人》
  9. OCEval-动态执行ObjectiveC的热修复方案
  10. 创建jenkins任务