信号是进程之间事件异步通知的一种方式,属于 软中断.为什么说异步呢?因为进程在运行的过程中,随时都有可能收到用户发送给内核的终止信号,当进程收到内核信号就会退出.
信号的产生方式
(1) 键盘按键产生,比如用户在shell命令下启动一个进程,然后按下 ctrl + c
,键盘输入产生一个硬件中断,被 OS 获取到,发送给目标前台进程,前台收到信号后使进程退出. 几乎每一个按键对于计算机来说都是一个信号
(2) 硬件产生信号:硬件如果异常被检测到后,会通知内核,内核向进程发送一个信号告诉它产生错误了,比如,解引用空指针,由于访问非法内存,MMU 会产生异常,告诉操作系统内核,内核将错误解释为11号信号(SIGSEGV),发送给进程,导致进程异常终止,再比如当前进程执行了除以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程.
(3) 软件条件产生信号:assert 函数里面有一个 abort 函数,如果内存错误或者受到限制,内核产生一个SIGABRT信号;如果管道读端关闭再进行写端则会触发一个管道破裂的信号SIGPIPE;alarm 是一个闹钟函数,告诉内核过一段时间给当前进程发SIGALRM信号,该信号被解释为终止当前进程
(4) 调用系统函数向进程发送一个信号,例如,kill 命令是调用 kill 函数实现的,kill 函数可以给一个指定的进程发送指定的信号 kill -SIGSEGV 4568
,再比如,raise 函数可以给当前进程发送指定的信号(也就是自己给自己发信号)int raise(int signo);
成功返回0,错误-1
处理信号
- 忽略此信号
- 执行信号默认处理动作
- 捕捉信号,自定以一个信号处理函数
忽略信号就是忽视它的存在,不做任何处理
默认处理就是按照它本来的意思处理,例:
SIGINT(2号进程)是终止进程;
SIGQUIT(3号信号)也是终止进程并且产生Core Dump 方便调试
使用 signal 函数捕捉信号
第一个参数是要捕捉的信号
第二个参数是对信号的处理方式
- SIG_DFL 执行该信号的默认处理动作
- SIG_IGN 忽略此信号
- 执行自定以信号的处理方式,如下图
#include <stdio.h>
#include