Linux下的信号处理

信号
程序在执行的时候,几乎任何时刻都会反生事件。
信号通常用来向一个进程通知事件。
信号是不可提前预知的,所以信号是异步的。
信号随时都可能发生,接收信号的进程也可以没有控制权。
每个信号名都以SIG开头,信号名的定义在<signal.h>中。
信号名一般都是宏,内部通常是一个正整数。
信号(signal)是一种软件中断,它提供了一种处理异步事件的方法,也是进程间惟一的异步通信方式。
通过命令 kill -l 可以查看到64个信号
Linux下的信号处理
而这些信号各自在什么条件下产生,默认的处理动作是什么,
在signal(7)中都有详细说明
man 7 signal
Linux下的信号处理
信号的值定义在signal.h中,在Linux中没有32和33这两个信号。
其中编号34以上的是实时信号,34以下的信号是普通信号。
可靠信号又称为实时信号
非可靠信号又称为非实时信号
在Linux系统中,信号的可靠性是指信号是否会丢失,或者说该信号是否支持排除。
SIGHUP( 1 ) ~ SIGSYS( 31 )之间的信号都是继承自UNIX系统是不可靠信号。
Linux系统根据POSIX标准定义了SIGRTMIN(34) ~ SIGRTMAX(64)之间的信号,它们都是可靠信号,也称为实时信号。
引发信号的情况
1.键盘事件 ctrl +c ctrl +
2.非法内存 如果内存管理出错,系统就会发送一个信号进行处理
3.硬件故障 同样的,硬件出现故障系统也会产生一个信号
4.环境切换 比如说从用户态切换到其他态,状态的改变也会发送一个信号,这个信号会告知给系统
信号的来源
1、程序的错误,如非法访问内存
2、外部信号,如按下了CTRL+C
3、通过kill或sigqueue向另一个进程发送信号(常用)
进程可以屏蔽掉大多数的信号,除了SIGSTOP和SIGKILL
SIGSTOP:使正在运行的进程暂停
SIGKILL:使正在运行的进程退出
信号的优先级
信号实质上是软中断,中断有优先级,信号也有优先级。
如果一个进程有多个未决信号,则对于同一个未决的实时信号,内核将按照发送的顺序来递送信号。
如果存在多个未决信号,则值(或者说编号)越小的越先被递送。
如果即存在不可靠信号,又存在可靠信号(实时信号),
虽然POSIX对这一情况没有明确规定,但Linux系统和大多数遵循POSIX标准的操作系统一样,将优先递送不可靠信号。
通过案例来观察信号
Linux下的信号处理
收到9号信号后,终止进程Linux下的信号处理
给进程发送9号信号Linux下的信号处理
信号未决

执行信号的处理动作称为信号递达(Delivery),信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞(Block)某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。注意,阻塞和忽略是不同,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。
回调函数
通过函数指针调用的函数称为回调函数
信号处理函数与相关结构
signal函数用于截取系统的信号,对此信号挂接用户自己定义的处理函数
#include<signal.h>
typedef void (*sighandler)(int);//函数指针
sighandler signal(int signum,sighandler handler);
signum 信号编号
sighandler 信号的处理函数
SIG_IGN 忽略信号
SIG_DFL 使用默认的信号处理函数
SIGINT捕获
程序中止信号,在用户按下Ctrl+C时发出
注意:可以使用Ctrl+\ 来退出(SIGQUIT)。
当我们按下:ctrl+\或kill –SIGQUIT pid发送SIGQUIT信号时,程序退出,那是因为进程对SIGQUIT信号的默认处理动作是退出程序。
signal函数
#include <signal.h>
typedef void(*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
第一个参数signum:指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号。  
第二个参数handler:描述了与信号关联的动作,它可以取以下两种:
(1)SIG_IGN   
这个符号表示忽略该信号。
#include <stdio.h>
#include <signal.h>
int main(int argc, char *argv[])
{
signal(SIGINT, SIG_IGN);
while (1);
return 0;
}
按下Ctrl+C,由于信号忽略了,程序并不退出,必须通过kill -9 pid来干掉它
2)SIG_DFL   
这个符号表示恢复对信号的系统默认处理。不写此处理函数默认也是执行系统默认操作。
#include <stdio.h>
#include <signal.h>
int main(int argc, char *argv[])
{
signal(SIGINT, SIG_DFL);
while (1);
return 0;
}
这时就可以按下CTRL +C 来终止该进程。把signal(SIGINT, SIG_DFL);这句去掉,效果是一样的.
注意:signal函数只影响当前进程
案例1:
屏蔽ctrl+!在这里插入图片描述

Linux下的信号处理
屏蔽ctrl+cLinux下的信号处理
Linux下的信号处理
案例2:
Linux下的信号处理
Linux下的信号处理
alarm触发SIGALRM信号
alarm(5);代表5秒后投递SIGALRM信号
alarm(0);代表信号作废,投递SIGALRM信号
案例3:

Linux下的信号处理
Linux下的信号处理
Linux下的信号处理