异步信号
锁、malloc 等不能在信号处理函数里用。这里涉及到 异步信号安全 (async-signal-safe) 的概念。
- 信号处理函数的执行环境
当一个信号到达进程时,内核 异步中断当前执行流,立即跳转到信号处理函数执行。
这意味着:
当前线程可能 正在持有锁(mutex、spinlock 等)
当前线程可能 正在使用 malloc/free,操作堆数据结构
- 为什么不能调用这些函数
锁(mutex 等)
如果信号处理函数里调用 pthread_mutex_lock():
线程可能已经在信号到达前持有这个锁
信号处理函数再次尝试加锁 → 死锁
malloc / free
malloc 内部会修改全局堆管理结构(如 free list)
如果信号到达时主程序正在调用 malloc 或 free,信号处理函数里再次调用 malloc/free → 堆数据结构可能被破坏
可能导致崩溃或内存泄漏
- async-signal-safe 函数
POSIX 定义了一组 “异步信号安全函数”(async-signal-safe functions)
信号处理函数中 只允许调用这些函数
常用安全函数示例:
_exit()
write()(低级系统调用,不会锁堆)
sig_atomic_t 类型变量赋值
总结
函数类型 | 可在信号处理函数里用? | 原因 |
---|---|---|
pthread_mutex_lock | ❌ | 可能已持锁 → 死锁 |
malloc/free | ❌ | 可能正在操作堆 → 数据结构破坏 |
write(fd, buf, n) | ✅ | 系统调用,不会破坏用户态结构 |
_exit() | ✅ | 安全终止进程 |
核心思想:信号是异步的,中断当前执行流,调用非 async-signal-safe 函数可能破坏正在执行的操作,导致不可预测的行为。