信号是一种软件中断,它提供了处理一种异步事件的方法,也是进程惟一的异步通信方式。在Linux系统中,根据POSIX标准扩展的信号机制,不仅可以用来通知某进程发生了什么事,还可以给进程传递数据。
信号的来源
信号的来源有很多种方式,基本可分为软件和硬件两种方式
- 硬件方式
- 当用户在终端按下某些键时,将会产生信号。如按下<Ctrl+C>组合键后将产生一个SIGINT信号
- 硬件异常产生信号:除数为0,无效的储存访问等。这些事件通常由硬件(如CPU)检测到,并将其通知给Linux操作系统内核,然后内核生成相应的信号,并把信号发送给该事件发生时正在运行的程序
2.软件方式
- 用户在终端下调用kill命令向进程发送任意信号
- 进程调用kill或sigqueue函数发送信号。
- 当检测到某种软件条件已经具备时发送信号,如由alarm或settimer设置的定时器超时时将生成SIGALRM信号
信号的种类
在shell下输入kill -l可显示Linux系统支持的全部信号
信号的值在signal.h种定义,上面这些信号的含义如下
SIGHUP(1号)至SIGSYS(31号)之间的信号都是继承自UNIX系统,是不可靠信号。Linux系统根据POSIX.4标准定义了SIGRTMIN (33号)与SIGRTMAX (64 号)之间的信号,它们都是可靠信号,也称为实时信号。我们注意到Linux下没有16和32号信号。
在Linux系统中,信号的可靠性是指信号是否会丢失,或者说该信号是否支持排队。当导致产生信号的事件发生时,内核就产生一个信号。 信号产生后,内核通常会在进程表中设置某种形式的标志。当内核设置了这个标志,我们就说内核向一个进程递送了一个信号。信号产生( generate)和递送(delivery) 之间的时间间隔,称为信号未决(pending)。
进程可以调用sigpending将信号设置为阻塞,如果为进程产生了一个阻塞的信号,而对该信号的动作是捕捉该信号(即不忽略信号),则内核将为该进程的此信号保持为未决状态,直到该进程对此信号解除阻塞或将对此信号的相应更改为忽略。如果在进程解除对某个信号的阻塞之前,这种信号发生了多次,那么如果信号被递送多次(即信号在未决信号队列里面排队),则称之为可靠信号,只被递送一次的信号成为不可靠信号。
信号实质上是软中断,中断有优先级,信号也有优先级。如果一个进程有多个未决信号,则对于同一个未决的实时信号, 内核将按照发送的顺序来递送信号。如果存在多个末决的实时信号,则值(或者说编号)越小的越先被递送。如果既存在不可靠信号,又存在可靠信号(实时信号),虽然POSIX对这情况没有明确规定,但Linux系统和大多数遵循POSIX标准的操作系统样, 将优先递送不可靠信号。
进程对信号的响应
当信号发生时,用户可以要求进程以下列三种方式之一对信号做出响应
- 捕捉信号。对于要捕捉的信号,可以为其指定信号处理函数,信号发生时该函数自动被调用,在该函数内部实现对该信号的处理。
- 忽略信号。大多数信号都可使用这种方式进行处理,但是SIGKILL和SIGSTOP这两个信号不能被忽略,同时这两个信号也不能被捕获和阻塞。此外,如果忽略某些由硬件异常产生的信号(如非法存储访问或除以0),则进程的行为是不可预测的。
- 按照系统默认方式处理。大部分信号的默认操作是终止进程,且所有的实时信号的默认动作都是终止进程。
本节主要是概念,下一节会具体涉及信号的处理的代码