信号处理对应的头文件为 signal.h
,通过其提供的 signal
函数可以设置信号的处理。
signal 函数声明如下:
typedef void (*__sighandler_t) (int)
__sighandler_t signal (int __sig, __sighandler_t __handler)
其中,
typedef void (*sighandler_t) (int)
定义了一个返回类型为void,参数类型为int的函数指针sighandler_t
。[1]sighandler_t signal (int sig, sighandler_t handler)
定义了一个返回类型为函数指针,参数分别为信号类型
和信号处理函数
的signal
函数。该函数被throw()
修饰,若抛出异常将引起程序中断。
signal
返回旧的 信号处理函数指针
,参数为 信号
和 信号处理函数指针
。当 signal
发生错误时,返回类型为 SIG_ERR
信号类型
其中,信号类型及其默认行为如下:[2]
信号类型 | 信号数值 | 信号说明 | 说明 |
---|---|---|---|
SIGUP | 1 | hangup | 许多服务进程在接受到该信号后会重新读取配置文件。但实际功能是通知进程它的控制终端被断开。缺省行为是终止进程。 |
SIGINT | 2 | interrupt | Shell的 |
SIGQUIT | 3 | quit | Shell的 |
SIGILL | 4 | illegal instr | 若执行的进程中包含非法指令,操作系统将向该进程发送SIGILL信号。可以尝试捕获该信号来协助调试。缺省行为是终止进程,并且创建一个核心转储。 |
SIGTRAP | 5 | trace trap | 用于调试目的。通知被调试进程达到断点。一旦该信号被交付,被调试的进程将停止,并且它的父进程将接到通知。缺省行为是终止进程,并且创建一个核心转储。 |
SIGABRT | 6 | abort() | 在异常终止(abort)一个进程的同时创建核心转储。然而如果该信号被捕获,并且信号处理句柄没有返回,那么进程不会终止。缺省行为是终止进程,并且创建一个核心转储。 |
SIGFPE | 8 | floating point exception | 当进程发生一个浮点错误时,SIGFPE信号被发送给该进程。对于那些处理复杂数学运算的程序,一般会建议你捕获该信号。缺省行为是终止进程,并且创建一个核心转储。 |
SIGKILL | 9 | kill | 该信号不能被捕获或忽略。一旦该信号被交付给一个进程,那么这个进程就会终止。但在处理一个“非中断操作”(比如磁盘I/O)可能不会终止进程。此时会造成进程死锁。缺省行为是终止进程。 |
SIGBUS | 10 | bus error | CPU检测到数据总线上的错误时将产生SIGBUS信号。当程序尝试去访问一个没有正确对齐的内存地址时就会产生该信号。缺省行为是终止进程,并且创建一个核心转储。 |
SIGSEGV | 11 | segmentation violation | 当程序没有权利访问一个受保护的内存地址时,或者访问无效的虚拟内存地址(脏指针,dirty pointers,译注:由于没有和后备存储器中内容进行同步而造成。关于野指针,可以参见http://en.wikipedia.org/wiki /Wild_pointer 的解释。)时,会产生这个信号。缺省行为是终止进程,并且创建一个核心转储。 |
SIGSYS | 12 | non-existent system call invoked | 进程执行一个不存在的系统调用时操作系统会交付该信号。缺省行为是终止进程,并且创建一个核心转储。 |
SIGPIPE | 13 | write on a pipe with no one to read it | 若进程尝试对管道执行写操作,然而管道的另一边却没有回应时,操作系统会将SIGPIPE信号交付给这个打算写入的进程。缺省行为是终止进程。 |
SIGALRM | 14 | alarm clock | 在进程的计时器到期的时候,SIGALRM信号会被交付给进程。缺省行为是终止进程。 |
SIGTERM | 15 | software termination signal from kill | 通知该进程终止,并且在终止之前做一些清理活动。SIGTERM信号是Unix的kill命令发送的缺省信号,同时也是操作系统关闭时向进程发送的缺省信号。缺省行为是终止进程。 |
SIGURG | 16 | urgent condition on IO channel | 在进程已打开的套接字上发生某些情况时,SIGURG将被发送给该进程。如果进程不捕获这个信号的话,那么将被丢弃。缺省行为是丢弃这个信号。 |
SIGSTOP | 17 | sendable stop signal not from tty | 本信号不能被捕获或忽略。一旦进程接收到SIGSTOP信号,它会被暂停,直到接收到另一个SIGCONT信号为止。缺省行为是暂停进程,直到接收到一个SIGCONT信号为止。 |
SIGTSTP | 18 | stop signal from tty | 暂停进程,Shell的 |
SIGCONT | 19 | continue a stopped process | 当进程停止的时候,这个信号用来告诉进程恢复运行。不能被忽略或阻塞,但可以被捕获。这样做很有意义:因为进程大概不愿意忽略或阻塞SIGCONT信号,否则,如果进程接收到SIGSTOP或SIGSTP的时候该怎么办?缺省行 为是丢弃该信号。 |
SIGCHLD | 20 | to parent on child stop or exit | SIGCHLD是由Berkeley Unix引入的,并且比SRV 4 Unix上的实现有更好的接口。(如果信号是一个没有追溯能力的过程(not a retroactive process),那么BSD的SIGCHID信号实现会比较好。在system V Unix的实现中,如果进程要求捕获该信号,操作系统会检查是否存在有任何未完成的子进程(这些子进程是已经退出exit)的子进程,并且在等待调用 wait的父进程收集它们的状态)。如果子进程退出的时候附带有一些终止信息(terminating information),那么信号处理句柄就会被调用。所以,仅仅要求捕获这个信号会导致信号处理句柄被调用(译注:即是上面说的“信号的追溯能 力”),而这是却一种相当混乱的状况。)一旦一个进程的子进程状态发生改变,SIGCHLD信号就会被发送给该进程。就像我在前面章节提到的,父进程虽然 可以fork出子进程,但没有必要等待子进程退出。一般来说这是不太好的,因为这样的话,一旦进程退出就可能会变成一个僵尸进程。可是如果父进程捕获 SIGCHLD信号的话,它就可以使用wait系列调用中的某一个去收集子进程状态,或者判断发生了什么事情。当发送SIGSTOP、SIGSTP或SIGCONF信号给子进程时,SIGCHLD信号也会被发送给父进程。缺省行为是丢弃该信号。 |
SIGTIIN | 21 | to readers pgrp upon background tty read | 当一个后台进程尝试进行一个读操作时,SIGTTIN信号被发送给该进程。进程将会阻塞直到接收到SIGCONT信号为止。缺省行为是停止进程,直到接收到SIGCONT信号。 |
SIGTTOU | 22 | like TTIN if (tp→t_local<OSTOP) | SIGTTOU信号与SIGTTIN很相似,不同之处在于SIGTTOU信号是由于后台进程尝试对一个设置了TOSTOP属性的tty执行写操作时才会 产生。然而,如果tty没有设置这个属性,SIGTTOU就不会被发送。缺省行为是停止进程,直到接收到SIGCONT信号。 |
SIGIO | 23 | input/output possible signal | 如果进程在一个文件描述符上有I/O操作的话,SIGIO信号将被发送给这个进程。进程可以通过fcntl调用来设置。缺省行为是丢弃该信 | |
SIGCPU | 24 | exceeded CPU time limit | 如果一旦进程超出了它可以使用的CPU限制(CPU limit),SIGXCPU信号就被发送给它。这个限制可以使用setrlimit设置。缺省行为是终止进程。 |
SIGXFSZ | 25 | exceeded file size limit | 如果一旦进程超出了它可以使用的文件大小限制,SIGXFSZ信号就被发送给它。稍后我们会继续讨论这个信号。缺省行为是终止进程 |
SIGVTALRM | 26 | virtual time alarm | 如果一旦进程超过了它设定的虚拟计时器计数时,SIGVTALRM信号就被发送给它。缺省行为是终止进程。 |
SIGPROF | 27 | profiling time alarm | 当设置了计时器时,SIGPROF是另一个将会发送给进程的信号。缺省行为是终止进程。 |
SIGWINCH | 28 | window size changes | 当进程调整了终端的尺寸时,SIGWINCH信号被发送给该进程。缺省行为是丢弃该信号。 |
SIGUSR1 | 29 | user defined signal 1 | 自定义信号,缺省行为是终止进程。 |
SIGUSR2 | 30 | user defined signal 2 | 自定义信号,缺省行为是终止进程。 |
信号 0 被用于 kill(pid, 0) 这个函数。用来在不发送信号的情况下测试进程是否存在 |
虚拟信号处理函数
除了自定义信号处理函数外,还有三个虚拟信号处理函数(fake signal functions):[3]
函数指针 | 函数定义 | 函数说明, 解释 |
---|---|---|
SIG_ERR | (__sighandler_t) -1) | Error return |
SIG_DFL | (__sighandler_t) 0 | Default action |
SIG_IGN | ((__sighandler_t) 1) | Ignore signal |
SIG_HOLD | ((__sighandler_t) 2) | Add signal to hold mask |
触发信号
使用 raise
可以向自己的程序发送信号,其声明如下:
int raise (int __sig);
例如:
#include <signal.h>
int main() {
signal(SIGINT, sig2);
raise(SIGINT);
return 0;
}
输出如下:
信号中断!