信号及信号来源
信号是在软件层次上对中断机制的一种模拟,在原理上,一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。信号是异步的,一个进程不必通过任何操作来等待信号的到达,事实上,进程也不知道信号到底什么时候到达。
信号是进程间通信机制中唯一的异步通信机制,可以看作是异步通知,通知接收信号的进程有哪些事情发生了。信号机制经过POSIX实时扩展后,功能更加强大,除了基本通知功能外,还可以传递附加信息。
信号事件的发生有两个来源:硬件来源(比如我们按下了键盘或者其它硬件故障);软件来源,最常用发送信号的系统函数是kill, raise, alarm和setitimer以及sigqueue函数,软件来源还包括一些非法运算等操作。
为了理解信号,先从我们最熟悉的场景说起:
1、用户输入命令,在Shell下启动一个前台进程。
2、用户按下Ctrl-C,这个键盘输入产生一个硬件中断。
3、如果CPU当前正在执行这个进程的代码,则该进程的用户空间代码暂停执行,CPU从用户态切换到内核态处理硬件中断。
4、终端驱动程序将Ctrl-C解释成一个SIGINT信号,记在该进程的PCB中(也可以说发送了一个SIGINT信号给该进程)。
当某个时刻要从内核返回到该进程的用户空间代码继续执行之前,首先处理PCB中记录的信号,发现有一个SIGINT信号待处理,而这个信号的默认处理动作是终止进程,所以直接终止进程而不再返回它的用户空间代码执行。
注意,Ctrl-C产生的信号只能发给前台进程。一个命令后面加个&可以放到后台运行,这样Shell不必等待进程结束就可以接受新的命令,启动新的进程。Shell可以同时运行一个前台进程和任意多个后台进程,只有前台进程才能接到像Ctrl-C这种控制键产生的信号。前台进程在运行过程中用户随时可能按下Ctrl-C而产生一个信号,也就是说该进程的用户空间代码执行到任何地方都有可能收到SIGINT信号而终止,所以信号相对于进程的控制流程来说是异步的。
用kill -l命令可以察看系统定义的信号列表:
每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定义#define SIGINT 2。编号34以上的是实时信号,我们目前只讨论编号34以下的信号,不讨论实时信号。这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明:
Signal Value Action Comment
-------------------------------------------------------------------------
SIGHUP 1 Term Hangupdetected on controlling terminalor death of controlling process
SIGINT 2 Term Interruptfrom keyboard
SIGQUIT 3 Core Quitfrom keyboard
SIGILL 4 Core IllegalInstruction
...
上表中第一列是各信号的宏定义名称,第二列是各信号的编号,第三列是默认处理动作,Term表示终止当前进程,Core表示终止当前进程并且Core Dump(下一节详细介绍什么是Core Dump),Ign表示忽略该信号,Stop表示停止当前进程,Cont表示继续执行先前停止的进程,表中最后一列是简要介绍,说明什么条件下产生该信号。
信号的种类
可以从两个不同的分类角度对信号进行分类:(1)可靠性方面:可靠信号与不可靠信号;(2)与时间的关系上:实时信号与非实时信号。
1、可靠信号与不可靠信号
"不可靠信号":Linux信号机制基本上是从Unix系统中继承过来的。早期Unix系统中的信号机制比较简单和原始,后来在实践中暴露出一些问题,因此,把那些建立在早期机制上的信号叫做"不可靠信号",信号值小于SIGRTMIN(Red hat 7.2中,SIGRTMIN=32,SIGRTMAX=63)的信号都是不可靠信号。这就是"不可靠信号"的来源。它的主要问题是:
进程每次处理信号后,就将对信号的响应设置为默认动作。在某些情况下,将导致对信号的错误处理;因此,用户如果不希望这样的操作,那么就要在信号处理函数结尾再一次调用signal(),重新安装该信号。
因此,早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。
Linux支持不可靠信号,但是对不可靠信号机制做了改进:在调用完信号处理函数后,不必重新调用该信号的安装函数(信号安装函数是在可靠机制上的实现)。因此,Linux下的不可靠信号问题主要指的是信号可能丢失。
"可靠信号":随着时间的发展,实践证明了有必要对信号的原始机制加以改进和扩充。所以,后来出现的各种Unix版本分别在这方面进行了研究,力图实现"可靠信号"。由于原来定义的信号已有许多应用,不好再做改动,最终只好又新增加了一些信号,并在一开始就把它们定义为可靠信号,这些信号支持排队,不会丢失。同时,信号的发送和安装也出现了新版本:信号发送函数sigqueue()及信号安装函数sigaction()。POSIX.4对可靠信号机制做了标准化。但是,POSIX只对可靠信号机制应具有的功能以及信号机制的对外接口做了标准化,对信号机制的实现没有作具体的规定。
信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。Linux在支持新版本的信号安装函数sigation()以及信号发送函数sigqueue()的同时,仍然支持早期的signal()信号安装函数,支持信号发送函数kill()。
注意:不要有这样的误解:由sigqueue()发送、sigaction安装的信号就是可靠的。事实上,可靠信号是指后来添加的新信号(信号值位于SIGRTMIN及SIGRTMAX之间);不可靠信号是信号值小于SIGRTMIN的信号。信号的可靠与不可靠只与信号值有关,与信号的发送及安装函数无关。目前linux中的signal()是通过sigation()函数实现的,因此,即使通过signal()安装的信号,在信号处理函数的结尾也不必再调用一次信号安装函数。同时,由signal()安装的实时信号支持排队,同样不会丢失。
对于目前linux的两个信号安装函数:signal()及sigaction()来说,它们都不能把SIGRTMIN以前的信号变成可靠信号(都不支持排队,仍有可能丢失,仍然是不可靠信号),而且对SIGRTMIN以后的信号都支持排队。这两个函数的最大区别在于,经过sigaction安装的信号都能传递信息给信号处理函数(对所有信号这一点都成立),而经过signal安装的信号却不能向信号处理函数传递信息。对于信号发送函数来说也是一样的。
2、实时信号与非实时信号
早期Unix系统只定义了32种信号,Ret hat7.2支持64种信号,编号0-63(SIGRTMIN=31,SIGRTMAX=63),将来可能进一步增加,这需要得到内核的支持。前32种信号已经有了预定义值,每个信号有了确定的用途及含义,并且每种信号都有各自的缺省动作。如按键盘的CTRL ^C时,会产生SIGINT信号,对该信号的默认反应就是进程终止。后32个信号表示实时信号,等同于前面阐述的可靠信号。这保证了发送的多个实时信号都被接收。实时信号是POSIX标准的一部分,可用于应用进程。
非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。
产生信号的条件主要有:
1、用户在终端按下某些键时,终端驱动程序会发送信号给前台进程,例如Ctrl-C产生SIGINT信号,Ctrl-\产生SIGQUIT信号,Ctrl-Z产生SIGTSTP信号,这个信号可使前台进程停止。
2、硬件异常产生信号,这些条件由硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号发送给进程。再比如当前进程访问了非法内存地址,,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
3、一个进程调用kill(2)函数可以发送信号给另一个进程。
4、可以用kill(1)命令发送信号给某个进程,kill(1)命令也是调用kill(2)函数实现的,如果不明确指定信号则发送SIGTERM信号,该信号的默认处理动作是终止进程。
5、当内核检测到某种软件条件发生时也可以通过信号通知进程,例如闹钟超时产生SIGALRM信号,向读端已关闭的管道写数据时产生SIGPIPE信号。
如果不想按默认动作处理信号,用户程序可以调用sigaction(2)函数告诉内核如何处理某种信号(sigaction函数稍后详细介绍),可选的处理动作有以下三种:
1、忽略此信号。
2、执行该信号的默认处理动作。
3、提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式称为捕捉(Catch)一个信号。
linux系统编程之信号(七)
今天继续学习信号,主要是学习关于时间和定时器相关的函数的使用,关于这个实际上有很多内容,这里先简要进行说明,等之后再慢慢进行相关深入,也主要是为接下来要做的一个综合linux系统编程的例子做准备,好了 ...
linux系统编程之信号(一):中断与信号
一,什么是中断? 1.中断的基本概念 中断是指计算机在执行期间,系统内发生任何非寻常的或非预期的急需处理事件,使得CPU暂时中断当前正在执行的程序而转去执行相应的事件处理程序,待处理完毕后又返回原来被 ...
linux系统编程之信号(二)
经过了漫长的间歇,对于c语言的学习也被中断了很久,现实确实有很多的无耐,计划中的事情总会被打乱,但不管怎样,学习的道路是不能休止的,所以经过了一断温习后现在继续学习C语言,话不多说,进入正题: 信号分 ...
linux系统编程之信号(二):信号处理流程(产生、注册、注销、执行)
对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个阶段: 信号诞生 信号在进程中注册 信号在进程中的注销 信号处理函数执行 1 信号诞生 信号事件 ...
linux系统编程之信号(一)
今天起,开始新的知识的学习,对于上个系列进程的学习还差一个理论上的总结,这个会下次补回来,以便通过实践之后,再用理论将其巩固一下,好了,话不多说,开始进入这个主题的学习----信号,很重要,但不是太容 ...
linux系统编程之信号(七):被信号中断的系统调用和库函数处理方式
一些IO系统调用执行时, 如 read 等待输入期间, 如果收到一个信号,系统将中断read, 转而执行信号处理函数. 当信号处理返回后, 系统遇到了一个问题: 是重新开始这个系统调用, 还是 ...
linux系统编程之信号(三):信号安装、signal、kill,arise讲解
一,信号安装 如果进程要处理某一信号,那么就要在进程中安装该信号.安装信号主要用来确定信号值及进程针对该信号值的动作之间的映射关系,即进程将要处理哪个信号:该信号被传递给进程时,将执行何种操作. li ...
linux系统编程之信号(三)
今天继续对信号进行研究,话不多说,言归正传: 更多信号发送函数: 上节中我们已经接触到了一些信号的发送函数,这里更进一步学习一下其它的发送函数: alarm:只能发送SIGALRM信号 下面通过一个例 ...
linux系统编程之信号(八):三种时间结构及定时器setitimer()详解
一,三种时间结构 time_t://seconds struct timeval { long tv_sec; /* seconds */ long tv_usec; /* microsecond ...
linux系统编程之信号(六):信号发送函数sigqueue和信号安装函数sigaction
一,sigaction() #include int sigaction(int signum,const struct sigaction *act,struct ...
随机推荐
Linux的用户及用户组
一./etc/group下存储当前系统中所有的用户组信息 -Group: x : 123 :abc,def,xyz -组名称:组密码占位符:组编号:组中用户名列表 二./etc/gshado ...
交换机的link-dependency链路依赖功能
在生产环境中,如果各主机连接到交换机的1-16端口,交换机的18端口上联到外部网络,如果此时交换机的18端口断掉,在主机端网卡仍然有连接,对于一些网络的配置可能就感知不到外部连接的消失,会有问题(如E ...
ubuntu tomcat 部署java web
1,安装jdk apt-get install openjdk-7-jdk 2,下载tomcat.解压到对应的文件夹 3,将xxx.war放入到 tomcat下的 webapp目录下(此目录下不要有 ...
用cart(分类回归树)作为弱分类器实现adaboost
在之前的决策树到集成学习里我们说了决策树和集成学习的基本概念(用了adaboost昨晚集成学习的例子),其后我们分别学习了决策树分类原理和adaboost原理和实现, 上两篇我们学习了cart(决策分 ...
hdu 4648
求一个数列中 去掉一些连续的数之后 不改变对m取余后的值 就是求一个最长的连续子序列 对m取余后为0 我的方法可能比较水 #include #include
让app在ios6上具有ios7的扁平效果
使用cocoapods在工程中加入UI7Kit,关于UI7Kit请自行google. 加入到工程 如果没安装cocoapods,则安装.(http://www.cocoapods.org) 安装方法: ...
Tcl语言笔记之二
1,表达式 1.1 操作数 TCL表达式的操作数通常是整数或实数.整数一般是十进制的, 但如果整数的第一个字符是0(zero),那么TCL将把这个整数看作八进制的,如果前两个字符是0x则这个整数被看作 ...
[MicroPython]TurniBit开发板旋转按钮控制脱机摆动
一.实验目的: ?学习在PC机系统中扩展简单I/O 接口的方法 ?学习TurnipBit拼插编程 ?了解舵机工作原理 ?学习TurnipBit扩展板舵机和旋转按钮接线方式 二.所需原器件: ?Turn ...
[MapReduce_add_1] Windows 下开发 MapReduce 程序部署到集群
0. 说明 Windows 下开发 MapReduce 程序部署到集群 1. 前提 在本地开发的时候保证 resource 中包含以下配置文件,从集群的配置文件中拷贝 在 resource 中新建 ...
python学习 day011打卡 迭代器
本节的主要内容: 1.函数名的使用以及第一类对象 2.闭包 3.迭代器 一.函数名的运用. 函数名是一个变量,但它是一个特殊的变量,与括号配合可以执行函数的变量. 1.函数名的内存地址 def fun ...