在 Linux 和 Unix 系统中,信号(Signal) 是一种进程间通信(IPC)机制,用于通知进程发生了某种事件。信号是一种异步的通知方式,操作系统或其他进程可以随时向目标进程发送信号,以让其执行特定的操作,如终止、暂停、继续运行等。
一) 什么是信号(Signals)?
- 信号是进程间的异步通知机制,可以用于通知进程某个事件发生,如中断、终止、挂起等。
- 进程可以接收、忽略、处理信号(但某些信号无法被捕获或忽略,如
SIGKILL
)。 - 信号是由 内核、用户、硬件 触发的。
- 进程可以使用
kill
命令或kill()
系统调用向其他进程发送信号。
二) 常见的 Linux 信号列表
信号编号 | 信号名称 | 默认动作 | 说明 |
---|---|---|---|
1 | SIGHUP |
终止 | 终端关闭、会话结束时发送 |
2 | SIGINT |
终止 | 用户按 Ctrl+C 终止进程 |
3 | SIGQUIT |
终止 + Dump | Ctrl+\ 退出进程,生成 core dump |
9 | SIGKILL |
终止 | 强制终止进程,不可捕获/忽略 |
11 | SIGSEGV |
终止 + Dump | 段错误(Segmentation Fault) |
15 | SIGTERM |
终止 | 默认的进程终止信号,可被捕获和忽略 |
18 | SIGCONT |
继续 | 让一个停止的进程继续运行 |
19 | SIGSTOP |
停止 | 强制暂停进程,不可捕获/忽略 |
20 | SIGTSTP |
停止 | Ctrl+Z 发送,让进程进入后台 |
The number of possible signals is limited. The first 31 signals are standardized in LINUX; all have names starting with SIG. Some are from POSIX.
# Signal Default Comment POSIX Name Action 1 SIGHUP Terminate Hang up controlling terminal or Yes process 2 SIGINT Terminate Interrupt from keyboard, Control-C Yes 3 SIGQUIT Dump Quit from keyboard, Control-\ Yes 4 SIGILL Dump Illegal instruction Yes 5 SIGTRAP Dump Breakpoint for debugging No 6 SIGABRT Dump Abnormal termination Yes 6 SIGIOT Dump Equivalent to SIGABRT No 7 SIGBUS Dump Bus error No 8 SIGFPE Dump Floating-point exception Yes 9 SIGKILL Terminate Forced-process termination Yes 10 SIGUSR1 Terminate Available to processes Yes 11 SIGSEGV Dump Invalid memory reference Yes 12 SIGUSR2 Terminate Available to processes Yes 13 SIGPIPE Terminate Write to pipe with no readers Yes 14 SIGALRM Terminate Real-timer clock Yes 15 SIGTERM Terminate Process termination Yes 16 SIGSTKFLT Terminate Coprocessor stack error No 17 SIGCHLD Ignore Child process stopped or terminated Yes or got a signal if traced 18 SIGCONT Continue Resume execution, if stopped Yes 19 SIGSTOP Stop Stop process execution, Ctrl-Z Yes 20 SIGTSTP Stop Stop process issued from tty Yes 21 SIGTTIN Stop Background process requires input Yes 22 SIGTTOU Stop Background process requires output Yes 23 SIGURG Ignore Urgent condition on socket No 24 SIGXCPU Dump CPU time limit exceeded No 25 SIGXFSZ Dump File size limit exceeded No 26 SIGVTALRM Terminate Virtual timer clock No 27 SIGPROF Terminate Profile timer clock No 28 SIGWINCH Ignore Window resizing No 29 SIGIO Terminate I/O now possible No 29 SIGPOLL Terminate Equivalent to SIGIO No 30 SIGPWR Terminate Power supply failure No 31 SIGSYS Dump Bad system call No 31 SIGUNUSED Dump Equivalent to SIGSYS No
Notice SIGUSR1 and SIGUSR2. These are available for customized use.
在终端运行kill -l命令, 可查看Linux支持的信号列表:

其中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的);编号为34 ~ 63的信号是后来扩充的,为可靠信号(实时信号)。
不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。
不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。
1 SIGHUP 挂起(在用户终端连接(正常或非正常)结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联)
2 SIGINT 中断(程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程)
3 SIGQUIT 退出(和SIGINT类似, 但由QUIT字符(通常是Ctrl-/)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号)
4 SIGILL 非法指令(执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号)
5 SIGTRAP 断点或陷阱指令(由断点指令或其它trap指令产生. 由debugger使用)
6 SIGABRT abort发出的信号(调用abort函数生成的信号)
7 SIGBUS 非法内存访问(非法地址, 包括内存地址对齐(alignment)出错。比如访问一个四个字长的整数, 但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法存储地址的非法访问触发的(如访问不属于自己存储空间或只读存储空间))
8 SIGFPE 浮点异常(在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误)
9 SIGKILL kill信号(用来立即结束程序的运行) 不能被忽略、处理和阻塞
10 SIGUSR1 用户信号1(留给用户使用)
11 SIGSEGV 无效内存访问(试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据)
12 SIGUSR2 用户信号2(留给用户使用)
13 SIGPIPE 管道破损,没有读端的管道写数据(这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止还往管道写,写进程会收到SIGPIPE信号。此外用Socket通信的两个进程,写进程在写Socket的时候,读进程已经终止,也会产生这个信号)
14 SIGALRM alarm发出的信号(时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号)
15 SIGTERM 终止信号(程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理。通常用来要求程序自己正常退出,shell命令kill缺省产生这个信号)
16 SIGSTKFLT 栈溢出
17 SIGCHLD 子进程退出(子进程结束时, 父进程会收到这个信号) 默认忽略
18 SIGCONT 进程继续 不能被阻塞
19 SIGSTOP 进程停止(停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行) 不能被忽略、处理和阻塞
20 SIGTSTP 进程停止(停止进程的运行, 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号) 该信号可以被处理和忽略
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 系统调用异常
参考博文:
三) 发送信号
3.1) kill
命令
kill
用于向进程发送信号:
kill -SIGNAL PID kill -9 1234 # 发送 SIGKILL 终止进程 1234 kill -15 5678 # 发送 SIGTERM(默认)终止进程 5678
如果不指定信号,默认发送 SIGTERM
:
kill 5678 # 等价于 kill -15 5678
3.2)pkill
和 killall
pkill
通过进程名发送信号:
pkill -9 firefox # 强制终止所有名为 firefox 的进程
killall
终止所有匹配名称的进程:
killall -15 python # 发送 SIGTERM 终止所有 Python 进程
3.3) kill()
系统调用
在 C 语言中,可以使用 kill()
发送信号:
#include <signal.h> #include <unistd.h> #include <stdio.h> int main() { pid_t pid = 1234; // 替换为目标进程 PID kill(pid, SIGKILL); // 向进程发送 SIGKILL return 0; }
3.4)raise()
向自己发送信号
#include <signal.h> #include <stdio.h> int main() { printf("Sending SIGTERM to self...\n"); raise(SIGTERM); // 进程向自己发送 SIGTERM return 0; }
3.5)sigqueue()
发送带数据的信号
#include <signal.h> #include <stdio.h> int main() { pid_t pid = 1234; // 目标进程 PID union sigval value; value.sival_int = 42; // 传递的数据 sigqueue(pid, SIGTERM, value); return 0; }
四) 处理信号
进程可以使用 signal()
或 sigaction()
处理信号。
4.1) signal()
处理信号
#include <signal.h> #include <stdio.h> #include <unistd.h> void handler(int signum) { printf("Received signal %d\n", signum); } int main() { signal(SIGINT, handler); // 捕获 SIGINT (Ctrl+C) while (1) { sleep(1); } return 0; }
运行后,按 Ctrl+C
发送 SIGINT
,进程不会终止,而是打印 Received signal 2
。
4.2) sigaction()
处理信号
sigaction()
提供更强的信号控制功能:
#include <signal.h> #include <stdio.h> #include <unistd.h> void handler(int signum) { printf("Caught signal %d\n", signum); } int main() { struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGINT, &sa, NULL); while (1) { sleep(1); } return 0; }
sigaction()
可以替代 signal()
,支持更高级的信号处理。
五)屏蔽信号
sigprocmask()
屏蔽信号
可以使用 sigprocmask()
屏蔽信号,使进程暂时忽略某些信号:
#include <signal.h> #include <stdio.h> #include <unistd.h> int main() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); // 屏蔽 SIGINT sigprocmask(SIG_BLOCK, &set, NULL); printf("SIGINT is blocked. Press Ctrl+C, but nothing happens.\n"); sleep(10); sigprocmask(SIG_UNBLOCK, &set, NULL); printf("SIGINT is now unblocked.\n"); while (1) sleep(1); return 0; }
SIG_BLOCK
屏蔽信号,SIG_UNBLOCK
解除屏蔽。
六) 挂起进程等待信号
6.1) pause()
等待信号
#include <signal.h> #include <stdio.h> #include <unistd.h> void handler(int signum) { printf("Caught signal %d, exiting...\n", signum); } int main() { signal(SIGINT, handler); printf("Waiting for signal...\n"); pause(); // 挂起进程,直到接收到信号 return 0; }
6.2) sigwait()
主动等待信号
#include <signal.h> #include <stdio.h> int main() { sigset_t set; int signum; sigemptyset(&set); sigaddset(&set, SIGINT); sigprocmask(SIG_BLOCK, &set, NULL); printf("Waiting for SIGINT...\n"); sigwait(&set, &signum); printf("Received signal %d\n", signum); return 0; }
7. 总结
- 信号是进程间通信的重要方式,用于通知进程发生事件,如终止、暂停、继续等。
- 进程可以使用
kill
、raise
、sigqueue
发送信号。 - 进程可以使用
signal()
或sigaction()
处理信号。 - 可以使用
sigprocmask()
屏蔽信号,pause()
或sigwait()
挂起进程等待信号。
掌握信号机制对编写可靠的后台服务、守护进程、异常处理等至关重要!