1. Linux 中的信号
信号这个概念在很早期的 Unix 系统上就有。它一般会从 1 开始编号,通常来说,信号编号是 1 到 31,这个编号在所有的 Unix 系统上都是一样的。
取值 | 名称 | 解释 | 默认动作 |
---|---|---|---|
1 | SIGHUP | 挂起 | |
2 | SIGINT | 中断 | |
3 | SIGQUIT | 退出 | |
4 | SIGILL | 非法指令 | |
5 | SIGTRAP | 断点或陷阱指令 | |
6 | SIGABRT | abort发出的信号 | |
7 | SIGBUS | 非法内存访问 | |
8 | SIGFPE | 浮点异常 | |
9 | SIGKILL | kill信号 | 不能被忽略、处理和阻塞 |
10 | SIGUSR1 | 用户信号1 | |
11 | SIGSEGV | 无效内存访问 | |
12 | SIGUSR2 | 用户信号2 | |
13 | SIGPIPE | 管道破损,没有读端的管道写数据 | |
14 | SIGALRM | alarm发出的信号 | |
15 | SIGTERM | 终止信号 | |
16 | SIGSTKFLT | 栈溢出 | |
17 | SIGCHLD | 子进程退出 | 默认忽略 |
18 | SIGCONT | 进程继续 | |
19 | SIGSTOP | 进程停止 | 不能被忽略、处理和阻塞 |
20 | SIGTSTP | 进程停止 | |
21 | SIGTTIN | 进程停止,后台进程从终端读数据时 | |
22 | SIGTTOU | 进程停止,后台进程想终端写数据时 | |
23 | SIGURG | I/O有紧急数据到达当前进程 | 默认忽略 |
24 | SIGXCPU | 进程的CPU时间片到期 | |
25 | SIGXFSZ | 文件大小的超出上限 | |
26 | SIGVTALRM | 虚拟时钟超时 | |
27 | SIGPROF | profile时钟超时 | |
28 | SIGWINCH | 窗口大小改变 | 默认忽略 |
29 | SIGIO | I/O相关 | |
30 | SIGPWR | 关机 | 默认忽略 |
31 | SIGSYS | 系统调用异常 |
用一句话来概括,信号(Signal)其实就是 Linux 进程收到的一个通知。这些通知产生的源头有很多种,通知的类型也有很多种。比如下面这几个典型的场景:
- 如果按下键盘“Ctrl+C”,当前运行的进程就会收到一个信号 SIGINT 而退出;
- 如果代码写得有问题,导致内存访问出错了,当前的进程就会收到另一个信号 SIGSEGV;
- 也可以通过命令 kill ,直接向一个进程发送一个信号,缺省情况下不指定信号的类型,那么这个信号就是 SIGTERM。也可以指定信号类型,比如命令 “kill -9 “, 这里的 9,就是编号为 9 的信号,SIGKILL 信号。
2. Linux内核对信号的处理是怎么样的
进程在收到信号后,就会去做相应的处理。对于每一个信号,进程对它的处理都有下面三个选择。
- 第一个选择是忽略(Ignore),就是对这个信号不做任何处理,但是有两个信号例外,对于 SIGKILL 和 SIGSTOP 这个两个信号,进程是不能忽略的。这是因为它们的主要作用是为 Linux kernel 和超级用户提供删除任意进程的特权。
- 第二个选择,就是捕获(Catch),这个是指让用户进程可以注册自己针对这个信号的 handler。对于捕获,SIGKILL 和 SIGSTOP 这两个信号也同样例外,这两个信号不能有用户自己的处理代码,只能执行系统的缺省行为。
- 还有一个选择是缺省行为(Default),Linux 为每个信号都定义了一个缺省的行为,可以在 Linux 系统中运行 man 7 signal来查看每个信号的缺省行为。
对于大部分的信号而言,应用程序不需要注册自己的 handler,使用系统缺省定义行为就可以了。