信号的基本概念
信号(signal),又称为软中断信号,是进程间通信机制中唯一的异步通信机制,用于通知进程发生了异步事件, 它是Linux系统响应某些条件而产生的一个事件, 它是在软件层次上对中断机制的一种模拟,是一种异步通信方式,在原理上, 一个进程收到一个信号与处理器收到一个中断请求可以说是一样的。
系统支持的信号
从图中可以看出,Linux系统支持信号62种信号,每种信号名称都以SIG三个字符开头, 注意,编号为32和33的信号值是不存在的。
可以将这62中信号分为2大类:信号值为1~31的信号属性非实时信号(也称为不可靠信号), 它们是从UNIX系统中继承下来的信号,具体的作用见下表, 信号值为34~64的信号为实时信号(也被称为可靠信号)。
信号值 | 名称 | 描述 | 默认处理 |
---|---|---|---|
1 | SIGHUP | 控制终端被关闭时产生。 | 终止 |
2 | SIGINT | 程序终止(interrupt)信号,在用户键入INTR字符(通常是Ctrl + C)时发出,用于通知前台进程组终止进程。 | 终止 |
3 | SIGQUIT | SIGQUIT 和SIGINT类似,但由QUIT字符(通常是Ctrl + )来控制,进程在因收到SIGQUIT退出时会产生core文件,在这个意义上类似于一个程序错误信号。 | 终止并产生转储文件(core文件) |
4 | SIGILL | CPU检测到某进程执行了非法指令时产生,通常是因为可执行文件本身出现错误, 或者试图执行数据段、堆栈溢出时也有可能产生这个信号。 | 终止并产生转储文件(core文件) |
5 | SIGTRAP | 由断点指令或其它trap指令产生,由debugger使用。 | 终止并产生转储文件(core文件) |
6 | SIGABRT | 调用系统函数 abort()时产生。 | 终止并产生转储文件(core文件) |
7 | SIGBUS | 总线错误时产生。一般是非法地址,包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数,但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间)。 | 终止并产生转储文件(core文件) |
8 | SIGFPE | 处理器出现致命的算术运算错误时产生,不仅包括浮点运算错误,还包括溢出及除数为0等其它所有的算术的错误。 | 终止并产生转储文件(core文件) |
9 | SIGKILL | 系统杀戮信号。用来立即结束程序的运行,本信号不能被阻塞、处理和忽略。如果管理员发现某个进程终止不了,可尝试发送这个信号将进程杀死。 | 终止 |
10 | SIGUSR1 | 用户自定义信号。 | 终止 |
11 | SIGSEGV | 访问非法内存时产生,进程试图访问未分配给自己的内存,或试图往没有写权限的内存地址写数据。 | 终止 |
12 | SIGUSR2 | 用户自定义信号。 | 终止 |
13 | SIGPIPE | 这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止,也会产生这个信号。 | 终止 |
14 | SIGALRM | 定时器到期信号,计算的是实际的时间或时钟时间,alarm函数使用该信号。 | 终止 |
15 | SIGTERM | 程序结束(terminate)信号,与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号,如果进程终止不了,才会尝试SIGKILL。 | 终止 |
16 | SIGSTKFLT | 已废弃。 | 终止 |
17 | SIGCHLD | 子进程暂停或终止时产生,父进程将收到这个信号,如果父进程没有处理这个信号,也没有等待(wait)子进程,子进程虽然终止,但是还会在内核进程表中占有表项,这时的子进程称为僵尸进程,这种情况我们应该避免。父进程默认是忽略SIGCHILD信号的,我们可以捕捉它,做成异步等待它派生的子进程终止,或者父进程先终止,这时子进程的终止自动由init进程来接管。 | 忽略 |
18 | SIGCONT | 系统恢复运行信号,让一个停止(stopped)的进程继续执行,本信号不能被阻塞,可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作 | 恢复运行 |
19 | SIGSTOP | 系统暂停信号,停止进程的执行。注意它和terminate以及interrupt的区别:该进程还未结束,只是暂停执行,本信号不能被阻塞,处理或忽略。 | 暂停 |
20 | SIGTSTP | 由控制终端发起的暂停信号,停止进程的运行,但该信号可以被处理和忽略,比如用户键入SUSP字符时(通常是Ctrl+Z)发出这个信号。 | 暂停 |
21 | SIGTTIN | 后台进程发起输入请求时控制终端产生该信号。 | 暂停 |
22 | SIGTTOU | 后台进程发起输出请求时控制终端产生该信号。 | 暂停 |
23 | SIGURG | 套接字上出现紧急数据时产生。 | 忽略 |
24 | SIGXCPU | 处理器占用时间超出限制值时产生。 | 终止并产生转储文件(core文件) |
25 | SIGXFSZ | 文件尺寸超出限制值时产生。 | 终止并产生转储文件(core文件) |
26 | SIGVTALRM | 由虚拟定时器产生的虚拟时钟信号,类似于SIGALRM,但是计算的是该进程占用的CPU时间。 | 终止 |
27 | SIGPROF | 类似于SIGALRM / SIGVTALRM,但包括该进程用的CPU时间以及系统调用的时间。 | 终止 |
28 | SIGWINCH | 窗口大小改变时发出。 | 忽略 |
29 | SIGIO | 文件描述符准备就绪, 可以开始进行输入/输出操作。 | 终止 |
30 | SIGPWR | 启动失败时产生。 | 终止 |
31 | SIGUNUSED | 非法的系统调用。 | 终止并产生转储文件(core文件) |
对于以上表格,有几点需要注意的地方:
信号的“值”在 x86、PowerPC 和 ARM平台下是有效的,但是别的平台的信号值也许跟这个表的不一致。
“描述”中注明的一些情况发生时会产生相应的信号,但并不是说该信号的产生就一定发生了这个事件。 事实上,任何进程都可以使用kill()函数来产生任何信号。
信号 SIGKILL 和 SIGSTOP 是两个特殊的信号,他们不能被忽略、阻塞或捕捉,只能按缺省动作来响应。
一般而言,信号的响应处理过程如下:如果该信号被阻塞,那么将该信号挂起, 不对其做任何处理,等到解除对其阻塞为止。如果该信号被捕获,那么进一步判断捕获的类型, 如果设置了响应函数,那么执行该响应函数;如果设置为忽略,那么直接丢弃该信号。 最后才执行信号的默认处理。