UNIX环境编程学习笔记(24)——信号处理进阶学习之信号集和进程信号屏蔽字
lienhua34
2014-11-03
1 信号传递过程
信号源为目标进程产生了一个信号,然后由内核来决定是否要将该信号传递给目标进程。从信号产生到传递给目标进程的流程图如图 1 所示,

图 1: 信号产生、传递到处理的流程图
进程可以阻塞信号的传递。当信号源为目标进程产生了一个信号之后,内核会执行依次执行下面操作,
1. 如果目标进程设置了忽略该信号,则内核直接将该信号丢弃。
2. 如果目标进程没有阻塞该信号,则内核将该信号传递给目标进程,由目标进程执行相对应操作。
3. 如果目标进程设置阻塞该信号,则内核将该信号放到目标进程的阻塞信号列表中,等待目标进程对该类型信号的下一步设置。若目标进程后续设置忽略该信号,则内核将该信号从目标进程的阻塞信号列表中移除并丢弃。若目标进程对该信号解除了阻塞,内核将该信号传递给目标进程进行相对应的操作。
在信号产生到信号传递给目标进程之间的时间间隔内,我们称该信号为未决的(pending)。
每个进程都有一个信号屏蔽字(signal mask),它规定了当前要阻塞传递给该进程的信号集。对于每种可能的信号,信号屏蔽字中都有一位与之对应。
2 信号集及其操作
POSIX.1 定义了一个数据类型sigset_t,用于表示信号集。另外,头文件 signal.h 提供了下列五个处理信号集的函数。
函数 sigemptyset 初始化由 set 指向的信号集,清除其中所有信号。
int sigemptyset(sigset_t *set);
返回值:若成功则返回0,若出错则返回-1
函数 sigfillset 初始化由 set 指向的信号集,使其包含所有信号。
int sigfillset(sigset_t *set);
返回值:若成功则返回0,若出错则返回-1
函数 sigaddset 将一个信号 signo 添加到现有信号集 set 中。
int sigaddset(sigset_t *set, int signo);
返回值:若成功则返回0,若出错则返回-1
函数 sigdelset 将一个信号 signo 从信号集 set 中删除。
int sigdelset(sigset_t *set, int signo);
返回值:若成功则返回0,若出错则返回-1
函数 sigismember 判断指定信号 signo 是否在信号集 set 中。
int sigismember(const sigset_t *set, int signo);
返回值:若真则返回1,若假则返回0,若出错则返回-1
3. sigprocmask 检 或设置进程的信号屏蔽字
调用 sigprocmask 函数可以检测或者设置进程的信号屏蔽字。
#include <signal.h>
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
返回值:若成功则返回0,若出错则返回-1
若 oset 参数是一个非空指针,则进程的当前信号屏蔽字将通过 oset 返回。若 set 参数是一个非空指针,则参数 how 将指示如何修改当前信号屏蔽字。how 的可选值如表 1 所示,
| how | 说明 |
| SIG_BLOCK | 该进程新的信号屏蔽字是其当前信号屏蔽字和 set 指向信号集的并集。 |
| SIG_UNBLOCK | 该进程的信号屏蔽字是当前信号屏蔽字和 set 所指向信号集补给的交集。set 包含了我们希望解除阻塞的信号。 |
| SIG_SETMASK | 该进程新的信号屏蔽字设置为 set 所指向的信号集。 |
下面我们来看一个例子。在下面的程序文件中先调用 sigprocmask 设置阻塞信号 SIGALRM,然后调用 alarm(2) 设置一个两秒钟的闹钟(两秒钟之后将向当前进程产生一个 SIGALRM 信号)。在睡眠 4 秒钟之后(此时应该已经产生了 SIGALRM 信号),调用 sigprocmask 函数解除对信号SIGALRM 的阻塞。
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h> static void
sig_alrm(int signo)
{
printf("received SIGALRM\n");
} int
main(void)
{
sigset_t sigset; sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
if (sigprocmask(SIG_BLOCK, &sigset, NULL) < ) {
printf("sigprocmask error: %s\n", strerror(errno));
exit(-);
} if (signal(SIGALRM, sig_alrm) < ) {
printf("signal error: %s\n", strerror(errno));
exit(-);
} alarm();
sleep();
printf("before unblock sigprocmask\n");
if (sigprocmask(SIG_UNBLOCK, &sigset, NULL) < ) {
printf("sigprocmask SIG_UNBLOCK error: %s\n", strerror(errno));
exit(-);
}
printf("before exit\n");
exit();
}
sigprocmaskdemo.c
编译该程序文件 sigprocmaskdemo.c,生成并执行文件 sigprocmaskdemo,
lienhua34:demo$ gcc -o sigprocmaskdemo sigprocmaskdemo.c
lienhua34:demo$ ./sigprocmaskdemo
before unblock sigprocmask
received SIGALRM
before exit
从上面的执行输出,我们看到信号 SIGALRM 是在调用 sigprocmask函 数 执 行 unblock 之 后 才 被 传 递 给 当 前 进 程 进 行 处 理 的。 如 果 我 们 将sigprocmaskdemo.c 中的sigprocemask(SIG_BLOCK, &sigset, NULL) 注释掉,编译执行,生成如下结果,
lienhua34:demo$ ./sigprocmaskdemo
received SIGALRM
before unblock sigprocmask
before exit
4 sigpending 获取进程未决的信号集
函数 sigpending 获取当前进程所有未决的信号。通过其 set 参数返回未决的信号集。
#include <signal.h>
int sigpending(sigset_t *set);
返回值:若成功则返回0,若出错则返回-1
下面我们来看一个例子,
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <signal.h> void
alrm_is_pending(const char *str)
{
sigset_t pendingsigset; printf("%s: ", str);
if (sigpending(&pendingsigset) < ) {
printf("sigpending error: %s\n", strerror(errno));
exit(-);
}
if (sigismember(&pendingsigset, SIGALRM)) {
printf("SIGALRM is pending\n");
} else {
printf("SIGALRM is not pending\n");
}
} int
main(void)
{
sigset_t sigset; sigemptyset(&sigset);
sigaddset(&sigset, SIGALRM);
if (sigprocmask(SIG_BLOCK, &sigset, NULL) < ) {
printf("sigprocmask error: %s\n", strerror(errno));
exit(-);
}
alrm_is_pending("before alarm");
alarm();
sleep();
alrm_is_pending("after alarm");
exit();
}
sigpendingdemo.c
编译该程序 sigpendingdemo.c,生成并执行文件 sigpendingdemo。从下面的运行结果,我们看到调用 alarm 函数产生信号 SIGALRM 之后,该信号在 sigpending 函数的 set 参数指向的信号集中。
lienhua34:demo$ gcc -o sigpendingdemo sigpendingdemo.c
lienhua34:demo$ ./sigpendingdemo
before alarm: SIGALRM is not pending
after alarm: SIGALRM is pending
(done)
UNIX环境编程学习笔记(24)——信号处理进阶学习之信号集和进程信号屏蔽字的更多相关文章
- APUE学习笔记5——信号、信号集和进程信号屏蔽字
1 信号传递过程 当引发信号的事件发生时(如软硬件异常.软件定时.终端产生信号或调用kill函数等等),会产生信号,内核会发送给目标进程. 在信号产生到信号传递给目标进程之间的时间间隔内,称该信号为未 ...
- UNIX基础知识--<<UNIX 环境编程>>读书笔记
1 shell程序就是位于应用软件与系统调用之间的程序 每个用户登录系统,系统就会为用户分配shell (用户的登录的口令文件 在 /etc/passwd 2 ls filename 运行原理 ...
- UNIX环境编程学习——反思认识
学习情况: 有关UNIX系统环境编程的学习时间用来非常长的时间.可是感觉效果还是不是太好,在中间经过了期末考试.用来非常长的时间用来学习专业课.就将该过程的学习放到了一边上,放假以后又回家造成了 ...
- Django:学习笔记(7)——模型进阶
Django:学习笔记(7)——模型进阶 模型的继承 我们在面向对象的编程中,一个很重要的的版块,就是类的继承.父类保存了所有子类共有的内容,子类通过继承它来减少冗余代码并进行灵活扩展. 在Djang ...
- amazeui学习笔记二(进阶开发5)--Web 组件开发规范Rules
amazeui学习笔记二(进阶开发5)--Web 组件开发规范Rules 一.总结 1.见名知意:见那些class名字知意,见函数名知意,见文件名知意 例如(HISTORY.md Web 组件更新历史 ...
- amazeui学习笔记二(进阶开发4)--JavaScript规范Rules
amazeui学习笔记二(进阶开发4)--JavaScript规范Rules 一.总结 1.注释规范总原则: As short as possible(如无必要,勿增注释):尽量提高代码本身的清晰性. ...
- amazeui学习笔记二(进阶开发3)--HTML/CSS规范Rules
amazeui学习笔记二(进阶开发3)--HTML/CSS规范Rules 一.总结 1.am:以 am 为命名空间 2.模块状态: {命名空间}-{模块名}-{状态描述} 3.子模块: {命名空间}- ...
- amazeui学习笔记二(进阶开发2)--Web组件简介Web Component
amazeui学习笔记二(进阶开发2)--Web组件简介Web Component 一.总结 1.amaze ui:amaze ui是一个web 组件, 由模板(hbs).样式(LESS).交互(JS ...
- amazeui学习笔记二(进阶开发1)--项目结构structure
amazeui学习笔记二(进阶开发1)--项目结构structure 一.总结 1.项目结构:是说的amazeui在github上面的项目结构,二次开发amazeui用 二.项目结构structure ...
随机推荐
- ARKit从入门到精通(6)-ARSession介绍
转载:http://blog.csdn.net/u013263917/article/details/73157082 ARSession是一个连接底层与AR视图之间的桥梁,其实ARSCNView内部 ...
- java开发篇---验证码
验证码的作用:防止恶意破解密码.刷票.论坛灌水.刷页. 有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试,实际上使用验证码是现在很多网站通行的方式(比如招商银行的网上个人银 ...
- [转]MySQL-5.7 Update语句详解
原文地址:https://www.cnblogs.com/tongxiaoda/p/7908977.html .语法 (1)单表 UPDATE [LOW_PRIORITY] [IGNORE] tabl ...
- HDFS只支持文件append操作, 而依赖HDFS的HBase如何完成增删改查功能
其实HBase/LevelDB等系统,背后都应用了Log-structured merge tree.HBase的写操作有两个步骤:1) 写入HLog(防止宕机丢失数据), 2) 写入对应的Memst ...
- 【Unity】自定义编辑器窗口——拓展编辑器功能
最近学习了Unity自定义编辑器窗口,下面简单总结,方便用到时回顾. 新建一个脚本: using UnityEngine; using System.Collections; using UnityE ...
- Python urllib2 proxy
在 正式并入某大公司之后,网络必须设置为统一的proxy,好的方面没看到,但是立即让我一的一个小工具不能工作了.在之前使用urllib2库,无需设置proxy,一切工作正常.在必须使用proxy之后, ...
- python MQTT 出现TypeError: payload must be a string, bytearray, int, float or None.
原因, MQTT 发布信息,是不能发布 对象的,只能发布 字符串,整形,浮点型这样的 解决方法 self.__mqtt__.publish("computex/iot/5100/DataTr ...
- Go Revel - Routing(路由)
`Routing`路由控制着请求应该由哪些控制器接受. 它在项目的`conf/routes`文件中定义. 格式为: (METHOD) (URL Pattern) (Controller.Action) ...
- Selenium (1) —— Selenium安装与测试(101 Tutorial)
Selenium (1) -- Selenium安装与测试(101 Tutorial) jvm版本: 1.8.0_65 selenium版本: v2.48.0 (Standalone Selenium ...
- 淘宝开放平台获取沙箱token
沙箱环境的文档都是错的,直接使用以下地址: 输入淘宝测试账号: sandbox_c_1 密码: taobao1234 https://login.tbsandbox.com/member/log ...