函数原型:

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

作用:

  用于在接收到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止。   The sigsuspend() function replaces the current signal mask of the calling thread with the set of signals pointed to by sigmask and then suspends the thread until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process. This will not cause any other signals that may have been pending on the process to become pending on the thread.   If the action is to terminate the process then sigsuspend() will never return. If the action is to execute a signal-catching function, thensigsuspend() will return after the signal-catching function returns, with the signal mask restored to the set that existed prior to thesigsuspend() call.   It is not possible to block signals that cannot be ignored. This is enforced by the system without causing an error to be indicated.   也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接收到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。


返回值:

  sigsuspend返回后将恢复调用之前的的信号掩码。信号处理函数完成后,进程将继续执行。该系统调用始终返回-1,并将errno设置为EINTR.   Since sigsuspend() suspends process execution indefinitely, there is no successful completion return value. If a return occurs, -1 is returned and errno is set to indicate the error.   The sigsuspend() function will fail if:   [EINTR]   A signal is caught by the calling process and control is returned from the signal-catching function.


也就是说,sigsuspend后,进程就挂在那里,等待着开放的信号的唤醒。系统在接受到信号后,马上就把现在的信号集还原为原来的,然后调用处理函数。


Stevens在《Unix环境高级编程》一书中是如是回答的“If a signal is caught and if the signal handler returns, then sigsuspend returns and the signal mask of the process is set to its value before the call to sigsuspend.”,由于sigsuspend是原子操作,所以这句给人的感觉就是先调用signal handler先返回,然后sigsuspend再返回。


[cpp] view plaincopyprint?
  1. int main(void) {  
  2.    sigset_t   newmask, oldmask, zeromask;  
  3.   
  4.    if (signal(SIGINT, sig_int) == SIG_ERR)  
  5.       err_sys("signal(SIGINT) error");  
  6.   
  7.    sigemptyset(&zeromask);  
  8.   
  9.    sigemptyset(&newmask);  
  10.    sigaddset(&newmask, SIGINT);  
  11.    /* block SIGINT and save current signal mask */  
  12.    if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)  
  13.       err_sys("SIG_BLOCK error");  
  14.   
  15.    /* critical region of code */  
  16.    pr_mask("in critical region: ");  
  17.   
  18.    /* allow all signals and pause */  
  19.    if (sigsuspend(&zeromask) != -1)  
  20.       err_sys("sigsuspend error");  
  21.    pr_mask("after return from sigsuspend: ");  
  22.   
  23.    /* reset signal mask which unblocks SIGINT */  
  24.    if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)  
  25.       err_sys("SIG_SETMASK error");  
  26.   
  27.    /* and continue processing ... */  
  28.    exit(0);  
  29. }  
  30.   
  31. static void sig_int(int signo) {  
  32.    pr_mask("\nin sig_int: ");  
  33.    return;  
  34. }  



 
结果:

[cpp] view plaincopyprint?
  1. $a.out  
  2. in critical region: SIGINT  
  3. ^C  
  4. in sig_int: SIGINT  
  5. after return from sigsuspend: SIGINT  


如果按照sig_handler先返回,那么SIGINT是不该被打印出来的,因为那时屏蔽字还没有恢复,所有信号都是不阻塞的。那么是Stevens说错了么?当然没有,只是Stevens没有说请在sigsuspend的原子操作中到底做了什么?
sigsuspend的整个原子操作过程为:
(1) 设置新的mask阻塞当前进程;
(2) 收到信号,恢复原先mask;
(3) 调用该进程设置的信号处理函数;
(4) 待信号处理函数返回后,sigsuspend返回。
大致就是上面这个过程,噢,原来signal handler是原子操作的一部分,而且是在恢复屏蔽字后执行的,所以上面的例子是没有问题的,Stevens说的也没错。由于Linux和Unix的千丝万缕的联系,所以在两个平台上绝大部分的系统调用的语义是一致的。上面的sigsuspend的原子操作也是从《深入理解Linux内核》一书中揣度出来的。书中的描述如下:

[cpp] view plaincopyprint?
  1. /*The sigsuspend( ) system call puts the process in the TASK_INTERRUPTIBLE state, after having blocked the standard signals specified 
  2.  by a bit mask array to which the mask parameter points. The process will wake up only when a nonignored, nonblocked signal is sent  
  3.  to it. The corresponding sys_sigsuspend( ) service routine executes these statements: 
  4. */  
  5.   
  6. mask &= ~(sigmask(SIGKILL) | sigmask(SIGSTOP));  
  7. spin_lock_irq(¤t->sigmask_lock);  
  8. saveset = current->blocked;  
  9. siginitset(¤t->blocked, mask);  
  10. recalc_sigpending(current);  
  11. spin_unlock_irq(¤t->sigmask_lock);  
  12. regs->eax = -EINTR;  
  13. while (1) {  
  14.     current->state = TASK_INTERRUPTIBLE;  
  15.     schedule(  );  
  16.     if (do_signal(regs, &saveset))  
  17.         return -EINTR;  
  18. }   




int sigsuspend(const sigset_t *sigmask);

此函数用于进程的挂起,sigmask指向一个信号集。当此函数被调用时,sigmask所指向的信号集中的信号将赋值给信号掩码。之后进程挂起。直到进程捕捉到信号,并调用处理函数返回时,函数sigsuspend返回。信号掩码恢复为信号调用前的值,同时将errno设为EINTR。进程结束信号可将其立即停止。

 

??

[cpp] view plaincopyprint?
  1. #include <stdio.h>  
  2. #include <signal.h>  
  3.   
  4. void checkset();  
  5. void func();  
  6. void main()  
  7. {  
  8.      sigset_tblockset,oldblockset,zeroset,pendmask;  
  9.      printf("pid:%ld\n",(long)getpid());  
  10.      signal(SIGINT,func);  
  11.   
  12.      sigemptyset(&blockset);  
  13.      sigemptyset(&zeroset);  
  14.      sigaddset(&blockset,SIGINT);  
  15.   
  16.      sigprocmask(SIG_SETMASK,&blockset,&oldblockset);  
  17.      checkset();  
  18.      sigpending(&pendmask);  
  19.   
  20.      if(sigismember(&pendmask,SIGINT))  
  21.          printf("SIGINTpending\n");  
  22.   
  23.      if(sigsuspend(&zeroset)!= -1)  
  24.      {  
  25.      printf("sigsuspenderror\n");  
  26.      exit(0);  
  27.      }  
  28.   
  29.      printf("afterreturn\n");  
  30.      sigprocmask(SIG_SETMASK,&oldblockset,NULL);  
  31.   
  32.      printf("SIGINTunblocked\n");  
  33. }  
  34.   
  35. void checkset()  
  36. {    sigset_tset;  
  37.      printf("checksetstart:\n");  
  38.      if(sigprocmask(0,NULL,&set)<0)  
  39.      {  
  40.      printf("checksetsigprocmask error!!\n");  
  41.      exit(0);  
  42.      }  
  43.   
  44.      if(sigismember(&set,SIGINT))  
  45.      printf("sigint\n");  
  46.   
  47.      if(sigismember(&set,SIGTSTP))  
  48.      printf("sigtstp\n");  
  49.   
  50.      if(sigismember(&set,SIGTERM))  
  51.      printf("sigterm\n");  
  52.      printf("checksetend\n");  
  53. }  
  54.   
  55. void func()  
  56. {  
  57.      printf("hellofunc\n");  
  58. }  

linux c 之sigsuspend 进程阻塞相关推荐

  1. linux 查看进程阻塞,linux进程 阻塞和非阻塞操作

    在我们看全功能的 read 和 write 方法的实现之前, 我们触及的最后一点是决定何时使 进程睡眠. 有时实现正确的 unix 语义要求一个操作不阻塞, 即便它不能完全地进行下去. 有时还有调用进 ...

  2. linux write引起进程挂起,Linux设备驱动中的阻塞与非阻塞总结

    Linux设备驱动中的阻塞与非阻塞总结 阻塞操作是指,在执行设备操作时,若不能获得资源,则进程挂起直到满足可操作的条件再进行操作. 非阻塞操作的进程在不能进行设备操作时,并不挂起.被挂起的进程进入sl ...

  3. linux如何启动一个进程而不阻塞,当你在 Linux 上启动一个进程时会发生什么? | Linux 中国...

    原标题:当你在 Linux 上启动一个进程时会发生什么? | Linux 中国 本文是关于 fork 和 exec 是如何在 Unix 上工作的.你或许已经知道,也有人还不知道.几年前当我了解到这些时 ...

  4. linux编程取消wait函数,Linux编程基础之进程等待(wait()函数).pdf

    Linux编程基础之进程等待(wait()函数) 编程过程中,有时需要让一个进程等待另一个进程 ,最常见的是父进程等待自己的子进程 ,或者父进程回收自己 的子进程资源包括僵尸进程.这里简单介绍一下系统 ...

  5. vbs结束进程代码_物联网学习教程—Linux系统编程之进程控制

    Linux系统编程之进程控制 一.结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳 ...

  6. linux内核 current当前进程指针 task_struct结构介绍

    尽管内核模块不象应用程序一样顺序执行, 内核做的大部分动作是代表一个特定进程的. 内核代码可以引用当前进程, 通过存取全局项 current, 它在 <asm/current.h> 中定义 ...

  7. Linux下1号进程的前世(kernel_init)今生(init进程)----Linux进程的管理与调度

    Linux下有3个特殊的进程,idle进程(PID=0PID=0), init进程(PID=1PID=1)和kthreadd(PID=2PID=2) * idle进程由系统自动创建, 运行在内核态 i ...

  8. linux怎么监控守护进程,linux shell脚本守护进程监控svn服务

    最近搭建的svn服务不知道什么原因服务总是被关闭(如果你不知道怎么搭建svn可以参考linux下搭建svn版本控制软件),因此用shell脚本实现一个守护进程.用于监控svn服务是否启动,如果服务不在 ...

  9. linux下的僵尸进程处理SIGCHLD信号【转】

    转自:http://www.cnblogs.com/wuchanming/p/4020463.html 什么是僵尸进程? 首先内核会释放终止进程(调用了exit系统调用)所使用的所有存储区,关闭所有打 ...

最新文章

  1. UOJ 152 汉诺塔 分治
  2. 预告:DIY光剑第二阶段,大宝剑二号 ——爱与家庭,银色复仇者
  3. tableview的顶部有一部分空白区域,并不是Cell的解决方法。
  4. 使用equals判断对象是否相等出现的错误
  5. C语言auto、register、static、extern关键字
  6. android layout wrap_content,android-如果高度为WRAP_CONTENT,则不显示VideoVi...
  7. String变量的两种创建方式
  8. C语言 一元二次方程求解
  9. Hacking EV3系列之七:iPhone 手势无线控制LEGO EV3 Gyro Boy 机器人
  10. JAVA语言对接报警类语音通知接口demo示例
  11. 程序员去哪接私活?分享10个兼职平台,人已赚麻
  12. 给旧安卓手机安卓linux系统,手机秒变服务器(Linux Deploy)
  13. Nexus(maven私服)介绍、安装及使用教程
  14. 洛谷P1462 通往奥格瑞玛的道路 题解
  15. antd-vue的date-picker限制不能选择今天之前的时间
  16. 几种快速传输大文件的方式
  17. 单、双激光雷达启动与双激光雷达的外参标定(VLP-16)
  18. Fluent常用模型介绍-流体模拟仿真ansys
  19. java异常 — — 异常的处理
  20. Mysql并发插入引发的死锁

热门文章

  1. git提交过程中遇到的 index.lock 问题导致无法提交的解决方法
  2. Jfinal 2.1 集成 Guice,实现注解功能, 加入Service接口和实现类,直接晒代码
  3. SVN 之 去掉SVN管理标记
  4. 如何在Python上用jieba库分析TXT文件的词频
  5. spring的BeanWrapper类的原理和使用方法
  6. javascript 閉包
  7. 关于不能远程连接Linux中Mysql数据库的问题
  8. nyoj983 首尾相连数组的最大子数组和
  9. oracle数据源的报表sql计算慢解决
  10. 用Command实现校验器