Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5521149
  • 博文数量: 922
  • 博客积分: 19333
  • 博客等级: 上将
  • 技术积分: 11226
  • 用 户 组: 普通用户
  • 注册时间: 2007-03-27 14:33
文章分类

全部博文(922)

文章存档

2023年(1)

2020年(2)

2019年(1)

2017年(1)

2016年(3)

2015年(10)

2014年(17)

2013年(49)

2012年(291)

2011年(266)

2010年(95)

2009年(54)

2008年(132)

分类: LINUX

2012-01-22 20:22:03

++++++APUE读书笔记-10信号-04不可靠的信号++++++

 

4、不可靠的信号
================================================
 在早期的unix版本中,信号是不可靠的,也就是说,信号是容易丢失的(信号发生了,但是进程却不知道信号已经发生了);同时,进程对信号的控制也是有限的,进程只能获取或者忽略一个信号. 有时候我们需要告诉内核来阻塞一个信号,也就是说,产生信号的时候不忽略这个信号而是记住这个信号,当我们准备好了之后再告诉我们。
 在4.2BSD的时候,做了一些改变提供了可靠的信号机制,在SVR3的时候,有一套不同的改变的机制为SystemV实现可靠的信号机制,POSIX.1把BSD的模式作为了标准模式。
 早期的问题是,每当信号发生的时候,信号对应的动作会被重置为它的默认值.(在前面的例子中,当我们运行程序的时候,我们忽略了这个问题,只对信号捕捉一次),一般来说经典书籍里面早期系统中处理信号中断的代码大致如下:
      int     sig_int();        /* 自定义的信号处理函数 */
      ...
      signal(SIGINT, sig_int);  /* 建立信号处理函数和信号之间的联系 */
      ...
      sig_int()
      {
          signal(SIGINT, sig_int);  /* 再次建立处理函数和信号之间的联系 */
          ...                       /* 处理信号 ... */
      }
 (这里,信号处理函数返回int类型的原因是早期的系统不支持ISO C的void类型.)
 前面的代码片段的一个问题是,有一个时间窗口,它发生在信号产生的时候之后,信号处理函数时候调用signal再次建立信号处理函数连接之前;期间可能会再次发生一次信号。这第二次发生信号的时候,信号处理的函数已经被重置为默认的了,还没有来的及设置就被执行了(导致进程终止)。大多数时候,代码都能正常的工作,但是如果有这样的情况,我们就需要仔细考虑考虑了。
 另外一个问题就是,早期的系统进程,当它不想信号发生的时候,不能将一个信号“关闭”。所有进程只能忽略这个信号,有时后,我们想要告诉系统“阻止这些信号发生,但是当它们发生的时候把它们记住”。描述这个缺陷的典型的例子(捕获这个信号,然后为进程设置一个标记表明这个信号发生过):
       int     sig_int_flag;         /* 当信号发生的时候将这里设置为非0 */

       main()
       {
           int      sig_int();       /* 自定义的信号处理函数 */
           ...
           signal(SIGINT, sig_int);  /* 建立信号和处理函数之间的联系 */
           ...
           while (sig_int_flag == 0)
               pause();              /* 暂停,等待信号发生就进入下一次循环 */
           ...
       }

       sig_int()
       {
           signal(SIGINT, sig_int);  /* 再次建立处理函数和信号之间的联系 */
           sig_int_flag = 1;         /* 设置main函数中的循环检测的标记 */
       }
 这里的例子,进程调用pause函数进入睡眠等待一直到捕捉了一个信号。当信号被捕捉的时候,信号处理函数会设置sig_int_flag为非0。这个进程在信号处理函数返回的时候,自动地被内核唤醒,然后会注意到标记变成了非0,然后做相应的处理。但是,存在一个可以导致问题的时间窗口:如果信号发生在检测sig_int_flag之后但是调用pause之前,那么进程就可能永远睡眠不会醒过来了(前提假设是信号不会再次发生了).这样,信号就丢失了,这就是另外一个问题。尽管这个问题发生的可能性很小,但是如果它发生了,那么就很难调试。

参考:

 

 

阅读(779) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~

vaqeteart2013-10-16 15:21:58

mark