多线程与信号
Linux信号基础快速总结
1. 信号是什么?
- 定义:轻量级进程间通信机制,用于通知进程特定事件发生(如用户输入、硬件异常、系统事件)。
- 特点:
✅ 异步传递(随时可能中断进程)
✅ 不可靠信号(标准信号不排队,可能丢失)
✅ 编号范围:131(标准信号),3264(实时信号)
2. 关键信号速查表
信号 | 编号 | 触发场景 | 默认动作 |
---|---|---|---|
SIGINT | 2 | Ctrl+C | 终止进程 |
SIGKILL | 9 | kill -9 | 强制终止(不可捕获) |
SIGTERM | 15 | 默认终止命令(kill 无参数) | 终止进程 |
SIGSTOP | 19 | Ctrl+Z | 暂停进程(不可捕获) |
SIGSEGV | 11 | 非法内存访问(段错误) | 终止+核心转储 |
SIGCHLD | 17 | 子进程状态变化 | 忽略 |
SIGALRM | 14 | 定时器超时(alarm() ) | 终止进程 |
3. 信号处理三要素
-
默认行为
- 终止进程(如
SIGTERM
) - 暂停进程(如
SIGSTOP
) - 生成核心转储(如
SIGSEGV
)
- 终止进程(如
-
忽略信号
signal(SIGINT, SIG_IGN); // 忽略Ctrl+C
-
自定义处理函数
void handler(int sig) { /* 异步安全操作 */ } struct sigaction sa = {.sa_handler = handler,.sa_flags = SA_RESTART // 自动重启被中断的系统调用 }; sigaction(SIGINT, &sa, NULL);
4. 信号发送方式
- 命令行工具:
kill -SIGTERM 1234 # 向PID 1234发送SIGTERM killall -9 app_name # 强制终止所有名为app_name的进程
- 编程接口:
kill(pid, SIGUSR1); // 向指定进程发送信号 raise(SIGALRM); // 向当前进程发送信号(等同于kill(getpid(), sig))
5. 必须掌握的要点
-
不可捕获的信号:
SIGKILL
(9)和SIGSTOP
(19)无法被捕获、阻塞或忽略,用于强制控制进程。 -
异步安全函数:
信号处理函数中只能调用异步安全函数(如write()
、_exit()
),禁止使用printf()
、malloc()
等。 -
信号阻塞:
sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); sigprocmask(SIG_BLOCK, &set, NULL); // 阻塞SIGINT
-
实时信号(RT Signal):
- 支持排队(不丢失多次发送)
- 可携带额外数据(通过
sigqueue()
发送)
6. 多线程与信号
- 信号屏蔽:每个线程独立设置信号屏蔽字
pthread_sigmask(SIG_BLOCK, &set, NULL); // 当前线程屏蔽信号
- 信号处理:所有线程共享同一信号处理函数。
- 定向发送:
pthread_kill(thread_id, SIGUSR1); // 向指定线程发送信号
7. 核心实践原则
-
精简处理函数:仅设置标志位,避免复杂逻辑。
volatile sig_atomic_t flag = 0; // 原子类型确保线程安全 void handler(int sig) { flag = 1; }
-
处理被中断的系统调用:
while ((n = read(fd, buf, size)) < 0 && errno == EINTR); // 重启read()
-
避免信号竞争:关键代码段阻塞信号。
-
核心转储调试:
ulimit -c unlimited # 启用核心转储 gcc -g prog.c && ./a.out # 编译带调试信息 gdb ./a.out core # 分析崩溃原因
8. 常见问题
-
Q: 为什么
SIGKILL
无法被捕获?
A: 内核强制处理,防止进程拒绝终止。 -
Q: 多次发送
SIGINT
会丢失吗?
A: 是的,标准信号不排队,多次发送可能合并为一次。 -
Q: 如何优雅终止子进程?
A: 父进程捕获SIGCHLD
,调用waitpid()
回收资源。
9. 总结思维导图
Linux信号
├── 生命周期:生成 → 递送 → 处理
├── 关键操作
│ ├── 发送(kill/raise/sigqueue)
│ ├── 处理(默认/忽略/自定义)
│ └── 阻塞(sigprocmask)
├── 多线程
│ ├── 线程独立屏蔽信号
│ └── 全局处理函数
└── 安全原则├── 异步安全函数└── 原子标志传递
掌握这些核心知识,即可应对90%的信号相关开发与调试场景! 🚀