Linux 信号
概述
Linux 系统支持多种信号, 用于进程间通信、进程控制和异常处理. 信号分为两类:
- 标准信号 (1-31): POSIX 标准信号, 不排队, 可能丢失
- 实时信号 (SIGRTMIN 到 SIGRTMAX, 通常 34-64): 可以排队, 不会丢失
标准信号 (1-31)
| 编号 | 信号名 | 默认动作 | 说明 |
|---|---|---|---|
| 1 | SIGHUP | Terminate | 挂起信号. 当终端关闭或控制进程终止时发送. 常用于让守护进程重新读取配置文件 |
| 2 | SIGINT | Terminate | 中断信号. 通常由 Ctrl+C 触发. 用于请求进程终止 |
| 3 | SIGQUIT | Core | 退出信号. 通常由 Ctrl+\ 触发. 终止进程并生成 core dump |
| 4 | SIGILL | Core | 非法指令. 当进程尝试执行非法指令时由内核发送 |
| 5 | SIGTRAP | Core | 跟踪陷阱. 由调试器使用, 用于断点 |
| 6 | SIGABRT | Core | 中止信号. 由 abort() 函数发送, 用于异常终止 |
| 6 | SIGIOT | Core | 与 SIGABRT 相同 (历史遗留) |
| 7 | SIGBUS | Core | 总线错误. 访问无效内存地址时发送 (对齐错误等) |
| 8 | SIGFPE | Core | 浮点异常. 算术运算错误 (除零、溢出等) |
| 9 | SIGKILL | Terminate | 强制终止. 不可捕获、不可阻塞、不可忽略. 用于强制杀死进程 |
| 10 | SIGUSR1 | Terminate | 用户自定义信号 1. 应用程序可自由使用 |
| 11 | SIGSEGV | Core | 段错误. 访问无效内存地址时发送 |
| 12 | SIGUSR2 | Terminate | 用户自定义信号 2. 应用程序可自由使用 |
| 13 | SIGPIPE | Terminate | 管道破裂. 向已关闭的管道写入时发送 |
| 14 | SIGALRM | Terminate | 定时器信号. 由 alarm() 或 setitimer(ITIMER_REAL, ...) 触发 |
| 15 | SIGTERM | Terminate | 终止信号. 请求进程正常终止 (可捕获) |
| 16 | SIGSTKFLT | Terminate | 协处理器栈错误 (已废弃, 很少使用) |
| 17 | SIGCHLD | Ignore | 子进程状态改变. 子进程终止、停止或继续时发送给父进程 |
| 18 | SIGCONT | Ignore | 继续信号. 恢复被停止的进程. 不可阻塞 |
| 19 | SIGSTOP | Stop | 停止信号. 暂停进程执行. 不可捕获、不可阻塞、不可忽略 |
| 20 | SIGTSTP | Stop | 终端停止信号. 通常由 Ctrl+Z 触发, 暂停进程 |
| 21 | SIGTTIN | Stop | 后台进程尝试从终端读取时发送 |
| 22 | SIGTTOU | Stop | 后台进程尝试向终端写入时发送 |
| 23 | SIGURG | Ignore | 紧急数据. 套接字上有紧急数据到达时发送 |
| 24 | SIGXCPU | Core | CPU 时间超限. 进程超过 CPU 时间限制时发送 |
| 25 | SIGXFSZ | Core | 文件大小超限. 进程尝试创建超过文件大小限制的文件时发送 |
| 26 | SIGVTALRM | Terminate | 虚拟定时器. 由 setitimer(ITIMER_VIRTUAL, ...) 触发 |
| 27 | SIGPROF | Terminate | 性能分析定时器. 由 setitimer(ITIMER_PROF, ...) 触发 |
| 28 | SIGWINCH | Ignore | 窗口大小改变. 终端窗口大小改变时发送 |
| 29 | SIGIO | Terminate | I/O 就绪. 文件描述符可进行 I/O 操作时发送 |
| 29 | SIGPOLL | Terminate | 与 SIGIO 相同 (System V 名称) |
| 30 | SIGPWR | Terminate | 电源故障. 系统电源故障时发送 |
| 31 | SIGSYS | Core | 系统调用错误. 无效的系统调用时发送 |
| 31 | SIGUNUSED | Core | 未使用信号 (与 SIGSYS 相同, 历史遗留) |
默认动作说明
- Terminate: 终止进程
- Core: 终止进程并生成 core dump 文件
- Stop: 暂停进程执行 (进入 TASK_STOPPED 状态)
- Ignore: 忽略信号 (不执行任何操作)
特殊信号说明
不可捕获/阻塞的信号
- SIGKILL (9): 强制终止, 不可捕获、不可阻塞、不可忽略
- SIGSTOP (19): 强制停止, 不可捕获、不可阻塞、不可忽略
作业控制信号
以下信号用于作业控制 (shell 的前台/后台进程管理):
- SIGSTOP (19): 停止进程
- SIGTSTP (20): 终端停止 (可捕获)
- SIGTTIN (21): 后台读终端
- SIGTTOU (22): 后台写终端
- SIGCONT (18): 继续被停止的进程
注意:
SIGCONT会清除所有待处理的停止信号- 停止信号会清除待处理的
SIGCONT SIGCONT不可阻塞
用户自定义信号
- SIGUSR1 (10): 用户自定义信号 1
- SIGUSR2 (12): 用户自定义信号 2
这两个信号专门为应用程序保留, 默认行为是终止进程, 但可以被捕获和处理. 常用于进程间通信和自定义事件通知.
定时器信号
- SIGALRM (14) : 实时定时器 (
alarm(),setitimer(ITIMER_REAL, ...),timer_create()) - SIGVTALRM (26) : 虚拟定时器 (
setitimer(ITIMER_VIRTUAL, ...)) - SIGPROF (27) : 性能分析定时器 (
setitimer(ITIMER_PROF, ...))
实时信号 (SIGRTMIN 到 SIGRTMAX)
概述
实时信号是 POSIX.1b 扩展, 提供了比标准信号更强大的功能:
- 编号范围 :
SIGRTMIN(通常 34) 到SIGRTMAX(通常 64) - 可以排队: 多个相同信号可以排队, 不会丢失
- 传递数据 : 可以通过
sigqueue()传递额外数据 (siginfo_t) - FIFO 顺序: 按先进先出顺序传递
- 优先级: 实时信号优先于标准信号传递
实时信号编号
在大多数 Linux 系统上:
SIGRTMIN= 34SIGRTMAX= 64- 共 31 个实时信号 (34-64)
注意 : 实时信号的编号可能因系统而异, 应使用 SIGRTMIN 和 SIGRTMAX 宏, 而不是硬编码数值.
实时信号特点
-
排队机制:
- 标准信号不排队, 相同信号只保留一个
- 实时信号可以排队, 多个相同信号都会传递
-
数据传递:
cunion sigval { int sival_int; // 整数值 void *sival_ptr; // 指针值 }; -
使用方式:
c// 发送实时信号 (带数据) sigqueue(pid, SIGRTMIN, value); // 接收实时信号 (带数据) sigaction(sig, &sa, NULL); // 使用 SA_SIGINFO 标志 -
应用场景:
- 需要可靠传输的场景
- 需要传递额外数据的场景
- 需要多个相同信号排队的场景
信号分类总结
按用途分类
| 类别 | 信号 | 说明 |
|---|---|---|
| 终止信号 | SIGTERM, SIGINT, SIGQUIT, SIGHUP | 请求进程终止 |
| 强制终止 | SIGKILL | 强制杀死进程 |
| 异常信号 | SIGSEGV, SIGBUS, SIGFPE, SIGILL, SIGABRT | 程序异常 |
| 定时器信号 | SIGALRM, SIGVTALRM, SIGPROF | 定时器触发 |
| 作业控制 | SIGSTOP, SIGTSTP, SIGCONT, SIGTTIN, SIGTTOU | 进程控制 |
| I/O 信号 | SIGIO, SIGURG, SIGPIPE | I/O 事件 |
| 资源限制 | SIGXCPU, SIGXFSZ | 资源超限 |
| 用户自定义 | SIGUSR1, SIGUSR2 | 应用程序使用 |
| 实时信号 | SIGRTMIN 到 SIGRTMAX | 可排队信号 |
按默认动作分类
| 默认动作 | 信号数量 | 信号列表 |
|---|---|---|
| Terminate | 多数 | SIGTERM, SIGINT, SIGHUP, SIGUSR1, SIGUSR2, SIGALRM, SIGPIPE, SIGKILL, SIGVTALRM, SIGPROF, SIGIO, SIGPWR, SIGRTMIN-SIGRTMAX |
| Core | 8 | SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGXCPU, SIGXFSZ, SIGSYS |
| Stop | 4 | SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU |
| Ignore | 3 | SIGCHLD, SIGCONT, SIGURG, SIGWINCH |
信号发送方式
命令行
bash
# 发送信号给进程
kill -SIGTERM <pid> # 发送 SIGTERM
kill -15 <pid> # 发送信号 15 (SIGTERM)
kill -9 <pid> # 发送 SIGKILL (强制终止)
# 查看所有信号
kill -l
系统调用
c
// 发送标准信号
kill(pid, SIGTERM);
// 发送实时信号 (带数据)
sigqueue(pid, SIGRTMIN, value);
// 发送信号给进程组
killpg(pgrp, SIGTERM);
// 发送信号给自己
raise(SIGTERM);
注意事项
-
信号安全: 信号处理函数必须是信号安全的 (async-signal-safe)
- 可以使用:
write,_exit,alarm,signal等 - 避免使用:
printf,malloc,free等
- 可以使用:
-
信号丢失: 标准信号不排队, 可能丢失
- 如果需要可靠传输, 使用实时信号
-
不可捕获信号 :
SIGKILL和SIGSTOP不可捕获、阻塞或忽略 -
多线程: 在多线程程序中, 信号会发送到任意一个线程
- 使用
pthread_sigmask()在线程级别控制信号
- 使用
-
实时信号编号 : 不要硬编码实时信号编号, 使用
SIGRTMIN和SIGRTMAX宏
相关文档
man 7 signal- 信号概述man 2 kill- 发送信号man 2 sigaction- 注册信号处理man 2 sigqueue- 发送实时信号man 2 sigprocmask- 阻塞信号
参考
- POSIX.1-2001 标准
- Linux 内核源码:
include/asm-*/signal.h - Linux 内核源码:
kernel/signal.c