48

Linux信号处理机制

 4 years ago
source link: http://mp.weixin.qq.com/s?__biz=MzIwNTI2ODY5OA%3D%3D&%3Bmid=2649938895&%3Bidx=1&%3Bsn=49df9084530758636ddafb3dca2e9622
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

f6R7V3m.png!web 戳蓝字「TopCoder 」关注我们哦!

3euyM3Q.png!web

信号是一种异步处理的软中断,内核会发送给进程某些异步事件,这些异步事件可能来自硬件,比如除0或者访问了非法地址; 也可能来自其他进程或用户输入,比如ctrl+c。

信号是一种进程间通信机制,信号都有一个对应的默认处理行为,信号触发时,信号处理函数和进程正常的执行流程同时存在,这会给编程带来隐患,如果信号处理函数中调用了不可重入函数的话。信号同其他进程间通信技术(管道、共享内存)相比,传递的信息还是有限的,由于信息较少所以也方便管理,一般在系统管理中使用,比如终止或者恢复进程等。    ·

信号的默认处理操作有:

  • 显式地忽略信号:即内核将会丢弃该信号,信号不会对目标进程产生任何影响。

  • 终止进程:很多信号的默认处理是终止进程,即将进程杀死。

  • 生成核心转储文件并终止进程:进程被杀死,并且产生核心转储文件。核心转储文件记录了进程死亡现场的信息。用户可以使用核心转储文件来调试,分析进程死亡的原因。

  • 停止进程:停止进程不同于终止进程,终止进程是进程已经死亡,但是停止进程仅仅是使进程暂停,将进程的状态设置成TASK_STOPPED,一旦收到恢复执行的信号,进程还可以继续执行。

  • 恢复进程的执行:和停止进程相对应,某些信号可以使进程恢复执行。

如果想要自定义信号处理逻辑,可以使用signal/sigaction函数接口来设置信号处理函数。

Linux信号可以分为两类:可靠信号和不可靠信号,信号值在 [1,31] 之间的所有信号,都被称为不可靠信号;在 [SIGRTMIN,SIGRTMAX] 之间的信号,被称为可靠信号。这二者之间是如何实现的呢?

对于不可靠信号,内核用位图来记录该信号是否处于挂起状态。如果收到某不可靠信号,内核发现已经存在该信号处于未决状态,就会简单地丢弃该信号。因此发送不可靠信号,信号可能会丢失,即内核递送给目标进程的次数,可能小于信号发送的次数。对于可靠信号,内核内部有队列来维护,如果收到可靠信号,内核会将信号挂到相应的队列中,因此不会丢失。严格说来,内核也设有上限,挂起信号的个数也不能无限制地增大,因此只能说,在一定范围之内,可靠信号不会被丢弃。

信号未决状态是指 从生成信号到信息处理逻辑执行的这段时间。

常见的Linux信号如下(可以通过命令kill -l查看):

SIGHUP 1 终端挂起或控制进程终止。当用户退出Shell时,由该进程启动的所有进程都会收到这个信号,默认动作为终止进程。
SIGINT 2 键盘中断。当用户按下组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为终止进程。
SIGQUIT 3 键盘退出键被按下。当用户按下或组合键时,用户终端向正在运行中的由该终端启动的程序发出此信号。默认动作为退出程序。
SIGFPE 8 发生致命的运算错误时发出。不仅包括浮点运算错误,还包括溢出及除数为0等所有的算法错误。默认动作为终止进程并产生core文件。
SIGKILL 9 无条件终止进程。进程接收到该信号会立即终止,不进行清理和暂存工作。该信号不能被忽略、处理和阻塞,它向系统管理员提供了可以杀死任何进程的方法。
SIGALRM 14 定时器超时,默认动作为终止进程。
SIGTERM 15 程序结束信号,可以由 kill 命令产生。与SIGKILL不同的是,SIGTERM 信号可以被阻塞和终止,以便程序在退出前可以保存工作或清理临时文件等。

信号的执行时机

每个进程有一个对应的”信号表“的东东,当内核传递给进程信号时,会在该进程对应的信号表中写入信号,当进程由内核态切换到用户态时,会查信号表,如果有信号,则会执行信号处理逻辑。从信号生成到执行信号处理逻辑这段时间,信号是未决的。

在信号处理函数期间,有可能还会收到其他信号,当然也有可能再次收到正在处理的信号。如果在处理A信号期间再次收到A信号,会发生什么呢?

对于传统的System V信号机制,在信号处理期间,不会屏蔽对应的信号,而这就会引起信号处理函数的重入。这算是传统的System V信号机制的另一个弊端了。BSD信号处理机制修正了这个缺陷。当然了,BSD信号处理机制只是屏蔽了当前信号,并没有屏蔽当前信号以外的其他信号。

信号与线程

目前进程大都是多线程的,如果向某个多线程的进程发信号,到底由哪个线程来处理呢?

注意信号处理是属于进程维度的,我们都知道每个线程可以有自己的信号掩码,在POSIX标准下,发给进程的信号会在进程下某个未阻塞该信号的线程中随机选择。如果信号默认行为是终止操作,那么所有线程都会game over的,而不仅仅是接收到信号的那个线程。

注意这里讨论的信号和Java中的信号量不是一回事,Java中的 Semaphore 信号量是用来控制同时访问特定资源的线程数量,它通过协调各个线程,保证合理的使用公共资源。Semaphore可用作流量控制,特别是公共资源有限的应用场景,比如数据库连接。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK