信号
信号是软件中断。信号提供了一种处理异步事件的方法,属于异步事件的经典实例。
信号的名字都以SIG三个字符开头,例如SIGABRT是提前退出信号(进程调用abort函数产生),SIGALRM是闹钟信号(由alarm函数设置的计时器超时产生)。而Linux和Solaris都支持应用程序额外定义的信号。
在头文件
UNIX的早期版本提供的信号模型并不可靠;4.3BSD和SVR3对信号模型做了更改,增加了可靠信号机制,但是Berkeley和AT&T所做的更改之间并不兼容。幸运的是,POSIX.1对可靠信号例程进行了标准化。
信号的生命周期
从信号发送到信号处理函数的执行完毕。对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个重要的阶段,这三个阶段由四个重要事件来刻画:信号产生;信号在进程中注册完毕;信号在进程中的注销完毕;信号处理函数执行完毕。相邻两个事件的时间间隔构成信号生命周期的一个阶段。
当一个实时信号发送给一个进程时,不管该信号是否已经在进程中注册,都会被再注册一次,因此,信号不会丢失,因此,实时信号又叫做"可靠信 号"。这意味着同一个实时信号可以在同一个进程的未决信号信息链中占有多个sigqueue结构(进程每收到一个实时信号,都会为它分配一个结构来登记该 信号信息,并把该结构添加在未决信号链尾,即所有诞生的实时信号都会在目标进程中注册);当一个非实时信号发送给一个进程时,如果该信号已经在进程中注 册,则该信号将被丢弃,造成信号丢失。因此,非实时信号又叫做"不可靠信号"。这意味着同一个非实时信号在进程的未决信号信息链中,至多占有一个 sigqueue结构(一个非实时信号产生后,1如果发现相同的信号已经在目标结构中注册,则不再注册,对于进程来说,相当于不知道本次信号发生,信号丢 失;2如果进程的未决信号中没有相同信号,则在进程中注册自己)。
需要注意的要点是:
1)信号注册与否,与发送信号的函数(如 kill()或 sigqueue()等)以及信号安装函数(signal()及sigaction())无关,只与信号值有关(信号值小于 SIGRTMIN的信号最多只注册一次,信号值在SIGRTMIN及SIGRTMAX之间的信号,只要被进程接收到就被注册)。
2)在信号被注销 到相应的信号处理函数执行完毕这段时间内,如果进程又收到同一信号多次,则对实时信号来说,每一次都会在进程中注册;而对于非实时信号来说,无论收到多少 次信号,都会视为只收到一个信号,只在进程中注册一次。当然还有有些需要知道的概念比如 低速系统调用,中断系统调用,可重入函数等等概念,请查阅环境高级编程。
信号的分类
信号的分类:
- 非可靠信号:早期unix下的不可靠信号主要指的是进程可能对信号做出错误的反应以及信号可能丢失。
- 可靠信号: 信号值位于SIGRTMIN和SIGRTMAX之间的信号都是可靠信号,可靠信号克服了信号可能丢失的问题。
注: 信号的可靠与不可靠只与信号值有关,与信号的发送及安装函数无关。当然也可以称为实时信号或者非实时信号,非实时信号都不支持排队,都是不可靠信号;实 时信号都支持排队,都是可靠信号。
产生信号的条件
产生信号的条件:
- 用户按下某些终端键时,引发终端产生信号。如按下DELETE键或Ctrl+C键产生中断信号(SIGINT)。
- 硬件异常产生信号,硬件检测到后通知内核,内核为该条件产生适当的信号:除数为0,而无效的内存引用产生SIGSEGV信号。
- 进程调用kill(2)函数可将信号发送给另一个进程或进程组。此时的接收信号进程和发送信号进程的所有者必须相同,或者发送信号进程的所有者为超级用户。
- 用户用kill(1)命令将信号发送给其他进程。此命令只是kill函数的接口,一般用于终止一个失控的后台进程。
- 当检测到某种软件条件已发生,并应将其通知有关进程时也产生信号。例如SIGURG信号(在网络连接上传来带外数据时产生)、SIGPIPE信号(在管道的读进程已终止后,一个进程写此管道时产生)、SIGALRM信号。
信号处理程序
进程不能简单地测试一个变量来判别是否出现一个信号,而是必须告诉内核“在此信号出现时请执行下列操作”。
具体可以按照三种方式处理,即信号的处理或信号相关的动作:
- 忽略此信号。大部分信号都可以使用该方法处理,但是SIGKILL和SIGSTOP不能被忽略,因为它们向超级用户提供了使进程终止或停止的可靠方法。另外,如果忽略某些硬件异常产生的信号,则进程的运行行为是未定义的。
- 捕捉信号。此时需要通知内核在信号发生时调用哪个用户函数。注意,不能捕捉SIGKILL和SIGSTOP信号。这时,调用的用户函数被成为信号处理程序或信号捕捉函数。
- 执行系统默认动作。针对大多数信号,系统的默认动作都是终止进程。
信号列表
Value | Signal | Description | |
1 | SIGHUP | 终止进程 | 发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送 |
2 | SIGINT | 终止进程 | 由Interrupt Key产生,通常是CTRL+C或者DELETE。发送给所有ForeGround Group的进程 |
3 | SIGQUIT | 建立CORE文件 | 输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程 |
4 | SIGILL | 建立CORE文件 | 非法指令异常 |
5 | SIGTRAP | 建立CORE文件 | 实现相关的硬件异常。一般是 调试异常 |
6 | SIGABRT/SIGIOT | 建立CORE文件 | 实现相关的硬件异常,或者由调用abort函数产生,进程非正常退出 |
7 | SIGBUS | 建立CORE文件 | 某种特定的硬件异常,通常由内存访问引起,包括内存地址对齐出错 |
8 | SIGFPE | 建立CORE文件 | 数学相关的异常,如被0除,浮点溢出,等等 |
9 | SIGKILL | 终止进程 | 立即结束进程的进行,无法阻塞、处理和忽略。 |
10 | SIGUSR1 | 终止进程 | 用户自定义signal 1 |
11 | SIGSEGV | 建立CORE文件 | 非法内存访问 |
12 | SIGUSR2 | 终止进程 | 用户自定义signal 2 |
13 | SIGPIPE | 终止进程 | 在reader中止之后写Pipe的时候发送 |
14 | SIGALRM | 终止进程 | 用alarm函数设置的 timer超时或setitimer函数设置的interval timer超时 |
15 | SIGTERM | 终止进程 | 请求中止进程,可以被阻塞和处理。Kill命令缺省发送该信号。 |
16 | SIGSTKFLT | Linux专用,数学协处 理器的栈异常 | |
17 | SIGCHLD | 忽略信号 | 进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略 |
18 | SIGCONT | 忽略信号 | 当stopped的进程恢复运行的时候,自动发送。信号不能被阻塞 |
19 | SIGSTOP | 停止进程 | 暂时停止进程。信号无法阻塞、处理和忽略。 |
20 | SIGTSTP | 停止进程 | Suspend Key,一般是Ctrl+Z。发送给所有Foreground Group的进程,可以阻塞、处理和忽略 |
21 | SIGTTIN | 停止进程 | 当Background Group的进程尝试读取Terminal的时候发送 |
22 | SIGTTOU | 停止进程 | 当Background Group的进程尝试写Terminal的时候发送 |
23 | SIGURG | 忽略信号 | 当“紧急”或out-of-band的数据被socket接收的时候可能发送 |
24 | SIGXCPU | 终止进程 | 当CPU时间限制超时的时候,可以由getrlimit/setrlimit来读取/改变 |
25 | SIGXFSZ | 终止进程 | 进程超过文件资源大小限制 |
26 | SIGVTALRM | 终止进程 | 虚拟时钟信号,计算的是进程占用CPU的时间。setitimer函数设置的Virtual Interval Timer超时的时候 |
27 | SIGPROF | 终止进程 | 相当于SIGALRM/SIGVTALRM,计算的是进程占用CPU时间和系统调用时间。Setitimer指定的Profiling Interval Timer所产生 |
28 | SIGWINCH | 忽略信号 | 当Terminal的窗口大 小改变的时候,发送给Foreground Group的所有进程 |
29 | SIGIO | 忽略信号 | 异步IO事件,文件描述符准备就绪,可以开始进行输入/输出操作 |
30 | SIGPWR | Power Failure,和系统相关。和UPS相关。 | |
31 | SIGSYS | 非法系统调用 | |
32 | |||
33 | |||
34 | SIGRTMIN | ||
SIGCANCEL | 由Solaris Thread Library内部使用,通常不会使用 | ||
SIGEMT | 和实现相关的硬件异常 | ||
SIGFREEZE | Solaris专用,Hiberate或者 Suspended时候发送 | ||
SIGINFO | BSD signal。由Status Key产生,通常是CTRL+T。发送给所有Foreground Group的进程 | ||
SIGLWP | 由Solaris Thread Libray内部使用 | ||
SIGPOLL | 当某个事件发送给Pollable Device的时候发送 | ||
SIGTHAW | Solaris专用,从Suspend恢复时候发送 | ||
SIGWAITING | Solaris Thread Library内部实现专用 | ||
SIGXRES | Solaris专用,进程超 过资源限制的时候发送 |
signal函数
点击(此处)折叠或打开
- #include <signal.h>
- void (*signal(int signo, void (*func) (int))) (int);
- 其中,signo参数就是UNIX系统的信号名,func的值是常量SIG_IGN(忽略此信号)、常量SIG_DFL(系统默认动作)或信号发生时调用的函数地址。
返回值:若成功则返回信号以前的处理配置(见下),若出错则返回SIG_ERR。