Chinaunix首页 | 论坛 | 博客
  • 博客访问: 232503
  • 博文数量: 35
  • 博客积分: 659
  • 博客等级: 上士
  • 技术积分: 357
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-01 21:16
文章分类
文章存档

2012年(12)

2011年(23)

分类: C/C++

2012-07-26 08:31:32

先来看看函数原型:

点击(此处)折叠或打开

  1. #include <signal.h>
  2. int     sigsuspend(const sigset_t *mask);

函数sigsuspend将进程的信号屏蔽码设置为mask,然后与pause()函数一样等待信号的发生并执行完信号处理函数。信号处理函数执行完后再把进程的信号屏蔽码设置为原来的屏蔽字,然后sigsuspend函数才返回。 Sigsuspend总是返回-1--------LinuxC编程实战》

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

注意,此函数没有成功返回值。如果它返回到调用者则总是返回-1,并将errno设置为EINTR(表示为一个被中断的系统调用) ------ UNIX环境高级编程》第二版

sigsuspend是一个原子操作

    (1)设置新的mask阻塞当前进程

    (2)收到信号,恢复原先mask

    (3)调用该进程设置的信号处理函数

    (4)待信号处理函数返回后,sigsuspend返回

理解suspend的功能就是将进程当前的屏蔽信号码设置为指定的信号set,让进程挂起,再等待一次非屏蔽的信号,接受到信号后,将信号屏蔽信号码恢复成原样。


sigsuspend的作用:

在运行一段程序时,我们可能想要让程序暂时的忽略某个信号,而后执行某个代码片断,执行后复原成原来的屏蔽信号码,接受原来可能在屏蔽其间所发出的被屏蔽掉的信号。

我们一开始可能想到的是用sigprocmask pause来完成,代码如下:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <signal.h>


  5. int main(void)
  6. {
  7.     sigset_t    newmask, oldmask;
  8.     
  9.     sigemptyset(&newmask);
  10.     sigaddset(&newmask, SIGINT);
  11.     

  12.     /*屏蔽SIGINT信号*/
  13.     if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0 ) {
  14.         perror("sigprocmask");
  15.         exit(-1);
  16.     }
  17.     
  18.     /*临界区*/
  19.     /*此处是不想被SIGINT信号中断的代码*/
  20.    /*-------code--------*/

  21.     /*将屏蔽的SIGINT信号恢复*/
  22.     if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) {
  23.         perror("sigprocmask");
  24.         exit(-1);
  25.     } 
  26.     /*用pause接受原来被屏蔽掉的SIGINT信号*/
  27.     pause();

  28.     return 0;
  29. }

但是这样做有个问题,当信号在pause()之前发出,如果该信号之发送了一次,那进程先会执行一次信号处理函数,然后将会在pause处永久挂起。

为了避免这种BUG,引入了sigsuspend(),该函数操作是一个原子操作,也就是说在执行该于原子操作其间,CPU不会进行线程切换,这样就不会被其它的线程所打断。

修改后的代码如下:

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <signal.h>

  4. void handler_sig(int signo);

  5. int main(void)
  6. {
  7.     sigset_t    newmask, oldmask, zeromask;

  8.     sigemptyset(&newmask);
  9.     sigemptyset(&zeromask);
  10.     sigaddset(&newmask, SIGINT);

  11.     /*安装信号函数*/
  12.     signal(SIGINT, handler_sig);


  13.     /*屏蔽SIGINT信号*/
  14.     if (-1 == sigprocmask(SIG_BLOCK, &newmask, &oldmask)) {
  15.         perror("sigprocmask");
  16.         exit(-1);
  17.     }

  18.     /*临界区*/
  19.     /*不想被SIGINT中断的代码*/
  20.    sleep(30);

  21.     /*用sigsuspend捕获在屏蔽期间内发出的信号,并完成相应的处理函数*/
  22.     if (-1 != sigsuspend(&zeromask)) {
  23.         perror("sigsuspend");
  24.         exit(-1);
  25.     }


  26.     /*恢复信号屏蔽*/
  27.     if (-1 == sigprocmask(SIG_SETMASK, &oldmask, NULL)) {
  28.         perror("sigprocmask");
  29.         exit(-1);
  30.     }


  31.     return 0;
  32. }

  33. void handler_sig(int signo)
  34. {
  35.     printf("revc SIGIO\n");
  36. }

程序在执行完相应的临界区代码后(此处临界区代码只写了sleep(30),只是为了保证之后在sleep期间收到SIGINT信号,实际中可根据需求加上相应的临界区代码),sigsuspend接收在临界区发出的信号,借着执行如下的原子操作

     1.屏蔽&zeromask信号集所包含的信号,此处为空,所以可以捕获所有的信号。

     2.捕获非屏蔽的信号,此处即捕获所有的信号。

     3.执行捕获到的信号所对应的信号处理函数。

     4.将当前所屏蔽的信号恢复成执行sigsuspend之前所屏蔽的信号。

     执行完4步操作后,程序结束,而不会想之前的程序停在pause()


sigsuspend在实际中还有很多应用,在此先介绍这一种用法,剩下日后遇到再补充。

阅读(3151) | 评论(1) | 转发(0) |
0

上一篇:DarkGDK 获取键盘输入-----dbKeyState();

下一篇:没有了

给主人留下些什么吧!~~

hbxm9772012-11-21 18:00:49

蛮深奥的