C++ 的 <csignal>
库提供了一种处理操作系统信号的机制,允许程序响应外部事件(如用户中断或程序错误)。它是从 C 语言的 <signal.h>
继承而来,属于 C++ 标准库的一部分,用于跨平台的基本信号处理。以下是详细介绍:
1. 核心功能
- 信号(Signal) :软件中断,由操作系统或程序自身触发的事件(例如
Ctrl+C
生成SIGINT
)。 - 信号处理函数(Signal Handler):用户定义的函数,用于响应特定信号。
- 发送信号 :程序可以通过
raise()
主动触发信号。
2. 主要组件
2.1 信号宏
<csignal>
定义了以下常见信号宏:
信号 | 描述 |
---|---|
SIGABRT |
程序异常终止(如 abort() 调用) |
SIGFPE |
算术运算错误(如除以零) |
SIGILL |
非法指令(如执行无效的机器指令) |
SIGINT |
交互式中断(如 Ctrl+C ) |
SIGSEGV |
无效内存访问(如解引用空指针) |
SIGTERM |
终止请求(如 kill 命令) |
2.2 函数
-
signal(int sig, void (*handler)(int))
注册信号处理函数。参数为信号编号和处理函数指针。
示例:
signal(SIGINT, handler_func);
-
int raise(int sig)
向当前程序发送信号
sig
。成功返回 0,失败返回非零。
3. 基本用法示例
cpp
#include <csignal>
#include <iostream>
#include <unistd.h> // 用于 sleep()
volatile sig_atomic_t flag = 0;
void signal_handler(int sig) {
if (sig == SIGINT) {
std::cout << "\nReceived SIGINT. Exiting gracefully...\n";
flag = 1;
}
}
int main() {
// 注册信号处理函数
signal(SIGINT, signal_handler);
std::cout << "Running. Press Ctrl+C to exit.\n";
while (!flag) {
sleep(1); // 模拟程序运行
}
return 0;
}
输出示例:
Running. Press Ctrl+C to exit.
^C
Received SIGINT. Exiting gracefully...
4. 注意事项
4.1 异步安全性(Async-Safety)
信号处理函数可能在任何时间点中断主程序,因此内部只能使用 异步安全函数 (如 write()
),避免使用 cout
、malloc
等非安全操作。
4.2 volatile sig_atomic_t
在信号处理函数和主程序之间共享变量时,应使用 volatile sig_atomic_t
类型,确保原子性和可见性。
4.3 可移植性
signal()
的行为因系统而异(如 Windows 和 Unix-like 系统差异)。- 推荐使用 POSIX 的
sigaction
(需<signal.h>
)替代signal()
,以获得更可靠的控制。
4.4 多线程环境
信号处理在多线程中行为复杂,通常建议在主线程统一处理信号,并避免在信号处理中操作共享资源。
5. 替代方案
- POSIX
sigaction
:提供更精细的信号控制(如阻塞信号、指定标志位)。 - C++ 异常:无法直接替代信号处理,但可通过将信号转换为异常(需谨慎)。
- Boost.Signals2:基于事件的信号/槽机制,适合高层应用逻辑。
6. 总结
<csignal>
是 C++ 中处理底层信号的轻量级工具,适合简单场景。对于复杂需求,建议结合系统特定的 API(如 sigaction
)或高级库。始终注意异步安全性和线程安全问题,避免不可预测的行为。