概念
信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。进程在接收到这个信号以后,可以设置响应的处理动作:忽略或者调用函数进行处理。
可以查看linux下的所有信号:一共64个信号,从1开始编号,其中也存在0号信号,但是0号信号是用来测试某个进程是否存在。其中1-32号信号是经典信号,不支持排队的(就是无论产生了多少次该信号都只当成一次处理),后面的32个信号是实时信号常用来驱动编程,并且是支持排队的(产生多少次就记录多少次,一次一次处理)
信号的产生
①终端的特殊按键:
Ctrl +c SIGINT
Ctrl +z SIGTSTP
Ctrl +\ SIGQUIT
②硬件系统故障产生:
段错误:非法的操作内存,然后操作系统发送11号信号提示段错误
浮点数例外:除0操作提示浮点数例外,CPU不能除0操作,否则发送8号信号终止进程。
③系统函数调用
Kill函数或者kill命令:(kill -信号编号 进程号)
向某一个进程或者进程组发送信号,但是这个时候只能向自己的进程发送信号,不能发送给其他进程。
root用户可以向所有进程发信号
④软件条件
某种软件引发的信号,每个进程有且仅有一个定时器
int raise(int sig );
函数向自己发送sig号信号
abort()调用进程自己向自己发送6号信号(sigabort)终止自己
unsigned int alarm(unsign int second )
函数的精度是秒,定时一个具体的second 秒数,到时之后给发送自己一个sigarm信号终止自己。
3.信号的处理
信号是由操作系统来处理的,说明信号的处理在内核态。信号不一定会立即被处理,此时会储存在信号的信号表中。
由上图中可看出信号有三种处理方式:
- 忽略
- 默认处理方式:操作系统设定的默认处理方式
- 自定义信号处理方式:可自定义信号处理函数,即提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数,这种方式成为捕捉(Catch)一个信号
- ①signal函数
#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
参数
- sig : 指定信号,也就是Linux那64个信号其中一个
- func: SIG_IGN忽略该信号,SIG_DFL采用系统默认方式处理信号,自定义的信号处理函数指针。
signal是一个带有sig和func两个参数的函数,func是一个类型为void (*)(int)的函数指针。该函数返回一个与func相同类型的指针,指向先前指定信号处理函数的函数指针。准备捕获的信号的参数由sig给出,接收到的指定信号后要调用的函数由参数func给出。其实这个函数的使用是相当简单的,通过下面的例子就可以知道。注意信号处理函数的原型必须为void func(int),或者是下面的特殊值:
SIG_IGN:忽略信号
SIG_DFL:恢复信号的默认行为
- ②sigaction函数
#include <signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
该函数与signal函数一样,用于设置与信号sig关联的动作,而oact如果不是空指针的话,就用它来保存原先对该信号的动作的位置,act则用于设置指定信号的动作
步骤
信号使用步骤:
- 在目的进程中安装信号,需要提供一个信号处理函数。
- 信号被某个进程产生。
- 操作系统响应信号,在目的进程中被注册。(信号在目的进程中被注册,操作系统将添加信号到目的进程的PCB的未决信号数据结构中)
- 信号在进程中注销,进程在执行信号处理函数之前,首先要把信号在进程中注销。
- 信号生命终止,保护上下文,进程捕获信号,即执行信号处理函数