目前linux中的signal()是通过sigation()函数实现的。

由signal()安装的实时信号支持排队,同样不会丢失。

先看signal 和 sigaction 的区别:

关键是

struct sigaction act;

里面有三个部分,除了 signal函数会关注的 sa_handler 之外,

还有 sa_mask,这里面可以提供阻塞功能(类似于sigprocmask)

  1. sigemptyset(&act.sa_mask);
  2. sigaddset(&act.sa_mask, SIGQUIT);

类似于:

sigset_t blockset;
sigemptyset(&blockset);
sigaddset(&blockset,SIGINT);
sigaddset(&blockset,SIGTSTP);

意思是在sigaction处理过程中,阻塞这些信号。

千万注意,开始我也理解错了,是阻塞不是屏蔽也不是忽略,在函数之后还是要处理的。

这样能够防止处理函数被打断。

被信号打断的函数会返回错误,errno是EINTR,如果不想手动处理,可以看下面这个sa_flags.

还有一个 sa_flags,如果 |= SA_RESTART 就能够自动重启被这个信号打断的函数。

sigaction调用的时候 sigaction(SIGINT, &act, 0);

第三个参数是 struct sigaction *oact,表示获得返回的原来的sigaction

信号内部实现:

下面这一篇对于信号的内部实现机制,讲的不错:

http://www.cnblogs.com/blueyunchao0618/p/5953862.html

当然,我之前的文章也讲的不错。可以看看。

信号的本质是软件层次上对中断的一种模拟(软中断)。它是一种异步通信的处理机制,事实上,进程并不知道信号何时到来。

2.信号来源

(1)程序错误,如非法访问内存

(2)外部信号,如按下了CTRL+C

(3)通过kill或sigqueue向另外一个进程发送信号

1. 信号的生命周期

信号产生->信号注册->信号在进程中注销->信号处理函数执行完毕

(2)信号注册

指的是在目标进程中注册,该目标进程中有未决信号的信息:

struct sigpending pending:
struct sigpending{
struct sigqueue *head, **tail;
sigset_t signal;
};

struct sigqueue{
struct sigqueue *next;
siginfo_t info;
}

注:也有地方写的是 *tail,未深究。

其中 sigqueue结构组成的链称之为未决信号链,sigset_t称之为未决信号集。

信号注册的过程就是将信号值加入到未决信号集siginfo_t中,将信号所携带的信息加入到未决信号链的某一个sigqueue中去。

对于可靠的信号,可能存在多个未决信号的sigqueue结构,对于每次信号到来都会注册。而不可靠信号只注册一次,只有一个sigqueue结构。

(3)信号在目标进程中注销

在进程的执行过程中,每次从系统调用或中断返回用户空间的时候,都会检查是否有信号没有被处理。如果这些信号没有被阻塞,那么就调用相应的信号处理函数来处理这些信号。

则调用信号处理函数之前,进程会把信号在未决信号链中的sigqueue结构卸掉。是否从未决信号集中把信号删除掉,对于实时信号与非实时信号是不相同的。

非实时信号:由于非实时信号在未决信号链中只有一个sigqueue结构,因此将它删除的同时将信号从未决信号集中删除。

实时信号:由于实时信号在未决信号链中可能有多个sigqueue结构,如果只有一个,也将信号从未决信号集中删除掉。如果有多个那么不从未决信号集中删除信号,注销完毕。

(3)处理过程:

程序运行在用户态时->进程由于系统调用或中断进入内核->转向用户态执行信号处理函数->信号处理函数完毕后进入内核->返回用户态继续执行程序

注:要多几次内核态切换。原因下面有写。

首先程序执行在用户态,在进程陷入内核并从内核返回的前夕,会去检查有没有信号没有被处理,如果有且没有被阻塞就会调用相应的信号处理程序去处理。首先,内核在用户栈上创建一个层,该层中将返回地址设置成信号处理函数的地址,这样,从内核返回用户态时,就会执行这个信号处理函数。当信号处理函数执行完,会再次进入内核,主要是检测有没有信号没有处理,以及恢复原先程序中断执行点,恢复内核栈等工作,这样,当从内核返回后便返回到原先程序执行的地方了。

注:上面也说明了,内核态下是可以访问用户栈的。

信号 signal sigaction补充的更多相关文章

  1. Linux进程间通信(一): 信号 signal()、sigaction()

    一.什么是信号 用过Windows的我们都知道,当我们无法正常结束一个程序时,可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢?同样的功能在Linux上是通过生成信号和捕获信号来实现的,运行中 ...

  2. signal, sigaction,信号集合操作

    信号是与一定的进程相联系的,而建立其信号和进程的对应关系,这就是信号的安装登记. Linux主要有两个函数实现信号的安装登记:signal和sigaction.其中signal在系统调用的基础上实现, ...

  3. Linux 信号signal处理函数

    转自:http://www.cnblogs.com/taobataoma/archive/2007/08/30/875662.html alarm(设置信号传送闹钟) 相关函数 signal,slee ...

  4. 进程间通信之信号量、消息队列、共享内存(system v的shm和mmap)+信号signal

    进程间通信方式有:System v unix提供3种进程间通信IPC:信号量.消息队列.共享内存.此外,传统方法:信号.管道.socket套接字. [注意上述6种方式只能用户层进程间通信.内核内部有类 ...

  5. Linux信号(signal)机制【转】

    转自:http://gityuan.com/2015/12/20/signal/ 信号(signal)是一种软中断,信号机制是进程间通信的一种方式,采用异步通信方式 一.信号类型 Linux系统共定义 ...

  6. Linux 信号signal处理函数--转

    alarm(设置信号传送闹钟)相关函数 signal,sleep 表头文件 #include<unistd.h> 定义函数 unsigned int alarm(unsigned int ...

  7. Python标准库07 信号 (signal包,部分os包)

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在了解了Linux的信号基础之后,Python标准库中的signal包就很容易学习 ...

  8. qt信号signal和槽slot机制

    内容: 一.概述 二.信号 三.槽 四.信号与槽的关联 五.元对象工具 六.程序样例 七.应注意的问题 信号与槽作为QT的核心机制在QT编程中有着广泛的应用,本文介绍了信号与槽的一些基本概念.元对象工 ...

  9. python进程间通信--信号Signal

    信号signal 是python进程间通信多种机制中的其中一种机制.可以对操作系统进程的控制,当进程中发生某种原因而中断时,可以异步处理这个异常. 信号通过注册的方式‘挂’在一个进程中,并且不会阻塞该 ...

随机推荐

  1. nginx配置aliyun https

    server { listen 443; server_name www.goforit.com goforit.com; ssl on; ssl_certificate cert/goforit.p ...

  2. neo4j nosql图数据库学习

    neo4j 文档:https://neo4j.com/docs/getting-started/current/cypher-intro/ 1.索引 # 给某类标签节点的属性添加索引 CREATE I ...

  3. 紫书 习题 10-14 UVa 10886(暴力+数据范围)

    开始的时候一看这题感觉很难,觉得肯定有什么很快的办法 不能暴力做(受了上一题10-13的影响) 然后一看那个函数感觉无从下手. 然后看了博客发现,原来这道题就是直接暴力-- 因为n的范围为10的7次方 ...

  4. 紫书 习题 10-13 UVa 11526(打表找规律+分步枚举)

    首先看这道题目,我预感商数肯定是有规律的排列的,于是我打表找一下规律 100 / 1 = 100 100 / 2 = 50  100 / 3 = 33  100 / 4 = 25  100 / 5 = ...

  5. gcc/g++命令参数笔记

    1. gcc -E source_file.c -E,只执行到预编译.直接输出预编译结果. 2. gcc -S source_file.c -S,只执行到源代码到汇编代码的转换,输出汇编代码. 3. ...

  6. Java基础学习总结(17)——线程

    一.线程的基本概念 线程理解:线程是一个程序里面不同的执行路径 每一个分支都叫做一个线程,main()叫做主分支,也叫主线程. 程只是一个静态的概念,机器上的一个.class文件,机器上的一个.exe ...

  7. myeclipse2013 jsp编辑初始化

    首先,大家可能有过这种经历.双击打开jsp编辑.它默认会打开视图,这样就使人恼火了,卡死了.所以我们能够自己设jsp的默认打开方式:打开Window-->preferences得: 搜索edit ...

  8. UvaLive 6600 Spanning trees in a secure lock pattern 矩阵行列式

    链接:https://icpcarchive.ecs.baylor.edu/index.php? option=com_onlinejudge&Itemid=8&page=show_p ...

  9. ubuntu server 网络配置,主机名配置

    一.通过命令ifconfig -a 查看可用网络设备 通过上面的命令,本机可用的网络设备为enp4s0f0 和enp4s0f1 ,不同的系统版本和硬件配置网络设备名可能不一样,所以一定要先确认本机可用 ...

  10. openSUSE leap 42.3 添加HP Laserjet Pro M128fn打印机和驱动

    一.安装驱动 YaST控制中心->软件管理->搜索->hplip 安装hplip 如下图: HPLIP(Linux Imaging and Printing Object)以前有hp ...