首页
登录 | 注册

信号屏蔽函数-------sigsuspend

先来看看函数原型:

  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在实际中还有很多应用,在此先介绍这一种用法,剩下日后遇到再补充。


相关文章

  • 作者:gfree.wind@gmail.com博客:linuxfocus.blog.chinaunix.net在软件开发的过程中,无论如何努力,bug几乎都是必不可少的.当某些bug发生时,该进程会产生coredump文件.通过这个core ...
  • 现象: linux下C++开发的网络服务器程序,在页面刷新时有时候会出现进程退出的情况.使用gdb调试,发现是系统发送了SIGPIPE信号,导致进程退出的. 规避或解决方法: 最根本的解决办法是提高socket编程recv或send函数的健 ...
  • Node.js 回调函数 Node.js 异步编程的直接体现就是回调. 异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了. 回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数. ...
  • 内建函数,顾名思义,就是编译器内部实现的函数.这些函数跟关键字一样,可以直接使用,无须像标准库函数那样,要 #include 对应的头文件才能使用. 用来处理变长参数列表: 用来处理程序运行异常: 程序的编译优化.性能优化: 查看函数运行中 ...
  • 实验环境:CentOS 6.7 1. 安装Ruby CentOS 6.7中默认安装的是Ruby 1.8,安装最新版2.2.3. root [ ~ ]# wget https://cache.ruby-lang.org/pub/ruby/2. ...
  • 作者:gfree.wind@gmail.com  博客:linuxfocus.blog.chinaunix.net在我们写代码的过程中,有很多函数由于经常的被调用,加上我们主观的惯性思维,认为这些函数很简单,结果反而更容易出错. 下面是我认 ...

2020 unjeep.com webmaster#unjeep.com
12 q. 0.012 s.
京ICP备10005923号