40-阻塞信号与未决信号
来源:互联网 发布:淘宝工作包括那些 编辑:程序博客网 时间:2024/05/21 21:36
有时候,你并不希望你的进程处理信号。比如接收到 SIGINT 后对它置之不理。linux 提供了一个函数 sigprocmask 来帮助我们实现此功能。
在一个进程中,保存了两个信号集(在PCB中),分别是阻塞信号集,还有一个未决信号集。当你使用 sigprocmask 的时候,就会修改阻塞信号集。有关未决信号集请阅读本文第 2 节。
如果一个信号加入阻塞信号集,该信号的信号处理函数就不会被调用。
1. sigprocmask 函数
此函数用于修改阻塞信号集。
1.1 函数原型
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
1.2 函数介绍
实际上,该函数不仅可以阻塞你指定的信号,也可以将之前阻塞的信号撤销。具体是通过 how 参数来控制的。
1.3 参数及返回值
how 参数
- SIG_BLOCK 该选项表示将 set 参数指示的信号集中的信号添加到进程阻塞集中
- SIG_UNBLOCK 该选项与功能 SIG_BLOCK 相反,表示将进程阻塞信号集中指定的信号删除
- SIG_SETMASK 该选项表示将进程阻塞信号集直接设定为你指定的 set
set 参数
表示你指定的信号集合
- oldset
返回旧的阻塞信号集
返回 int
0 表示成功,-1 失败。
2. 未决信号
初学者估计看到这个词就懵圈了,我第一次也挺懵圈,搞不懂为啥有些书把简单的东西搞复杂。
说的通俗点,未决信号,就是你的进程已经接收到了信号了,只是还没被信号处理函数处理的那些信号。
当你的进程一收到信号,它首先进入到未决信号集中(就是一个 sigset_t),当未决信号集中的信号被信号处理函数(你自己定义的或者系统默认的)处理,就会从未决信号集中删除。
你可以使用 sigpending 函数获取未决信号集。它的函数原型如下:
int sigpending(sigset_t *set);
使用起来也是相当简单。
3. 实例
该程序的功能是先把 SIGINT、SIGTSTP
加入到了进程阻塞信号集中去。接下来,每隔一秒打印一次未决信号集,第 10 次的时候,又把 SIGINT 信号从阻塞信号集中删除。
- 代码
// sigblock.c#include <unistd.h>#include <signal.h>#include <stdio.h>#include <stdlib.h>void printsigset(const sigset_t *set){ for (int i = 1; i <= 64; i++) { if (i==33) putchar(' '); if (sigismember(set, i) == 1) putchar('1'); else putchar('0'); } puts("");}void handler(int sig) { if (sig == SIGINT) printf("hello SIGINT\n"); if (sig == SIGQUIT) printf("hello SIGQUIT\n");}int main() { printf("I'm %d\n", getpid()); sigset_t st, oldst; sigemptyset(&st); sigaddset(&st, SIGINT); sigaddset(&st, SIGTSTP); sigprocmask(SIG_BLOCK, &st, &oldst); printf("new set:"); printsigset(&st); printf("old set:"); printsigset(&oldst); if (SIG_ERR == signal(SIGINT, handler)) { perror("signal SIGINT"); return 1; } if (SIG_ERR == signal(SIGQUIT, handler)) { perror("signal SIGQUIT"); return 1; } puts(""); int n = 0; while(1) { sigpending(&st); printsigset(&st); puts(""); sleep(1); if (n == 10) { sigset_t tmp; sigemptyset(&tmp); sigaddset(&tmp, SIGINT); sigprocmask(SIG_UNBLOCK, &tmp, NULL); } ++n; } return 0;}
- 编译和运行
$ gcc sigblock.c -o sigblock$ ./sigblock
运行过程中,按下 Ctrl + C
和 Ctrl + Z
程序都没反应,但是可以看到未决信号集中这两个信号比特位被置位。10 秒后,SIGINT 从阻塞信号集中被删除,即使没有按下 Ctrl + C
发送信号,信号处理函数也被执行,这之后发现未决非信号集中的 SIGINT 比特位被置 0.
- 结果
I'm 5939new set:01000000000000000001000000000000 00000000000000000000000000000000old set:00000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000^C01000000000000000000000000000000 00000000000000000000000000000000 // 此处按下了 ctrl c01000000000000000000000000000000 00000000000000000000000000000000^Z01000000000000000001000000000000 00000000000000000000000000000000 // 此处按下了 ctrl z^\hello SIGQUIT // 此处按下了 ctrl \01000000000000000001000000000000 0000000000000000000000000000000001000000000000000001000000000000 0000000000000000000000000000000001000000000000000001000000000000 0000000000000000000000000000000001000000000000000001000000000000 0000000000000000000000000000000001000000000000000001000000000000 0000000000000000000000000000000001000000000000000001000000000000 00000000000000000000000000000000hello SIGINT // 执行到这里 SIGINT 从阻塞信号集中被删除00000000000000000001000000000000 00000000000000000000000000000000
4. 总结
- 理解进程PCB的两个信号集(阻塞信号集和未决信号集)
- sigprocmask 用来修改阻塞信号集
- sigpending 用来获取未决信号集(不能修改)
最后,有两个信号是无法被阻塞的,你知道是哪两个信号吗?
- 40-阻塞信号与未决信号
- 信号“未决”与“阻塞”
- 信号“未决”与“阻塞”
- 信号“未决”与“阻塞”
- 信号“未决”与“阻塞”
- 信号未决与阻塞
- 未决信号与信号阻塞
- 未决信号与信号阻塞
- 信号未决与信号阻塞
- APUE:信号 - 未决信号与信号阻塞
- 关于信号未决与阻塞
- 信号的阻塞与未决
- 关于信号未决与阻塞
- linux信号阻塞与未决
- 信号的未决 阻塞
- 信号的未决 阻塞 .
- 信号未决与阻塞(二)
- (转载)【linux信号】信号未决与阻塞
- U3D多人镜头跟随, FC热血格斗,PC 地狱潜行者 的镜头 代码示例
- MVC框架设计(四)
- Android动态加载jar/dex
- linux下 C语言perror函数的作用
- Elasticsearch基础教程
- 40-阻塞信号与未决信号
- 并发和并行的区别
- 大斐波那契
- $.unblockUI()和ajax执行顺序问题
- 2017,一个新的开始,为自己,为家人
- Spring管理的bean初始化方法的三种方式,以及@PostConstruct不起作用的原因
- android studio中xml文件里所有android:开头的提示都消失的解决方案
- 报错:Your account already has a valid iOS Development certificate!
- JavaWeb 第12章 JDBC详解(五)高级应用