C++中处理信号需使用signal()或sigaction()注册处理函数,通过设置标志位实现安全响应,如捕获SIGINT进行优雅退出;推荐使用sigaction()以获得跨平台一致性,并遵守仅调用异步信号安全函数、避免复杂逻辑等规则,多线程环境下应结合pthread_sigmask与sigwait同步处理信号。

在C++程序中处理信号(如 SIGINT)通常使用标准C库函数 signal() 或更现代的 sigaction()。尽管C++没有内置的异常机制来直接捕获操作系统信号,但可以通过注册信号处理函数实现对中断、终止等事件的安全响应。
信号的基本概念与常见用途
信号是操作系统向进程发送的通知,用于告知某些事件发生。常见的信号包括:
- SIGINT:用户按下 Ctrl+C,请求中断程序
- SIGTERM:请求终止程序(可被捕获)
- SIGKILL:强制终止(不可捕获或忽略)
- SIGSEGV:段错误,访问非法内存
对于像 SIGINT 这类可捕获信号,我们可以注册处理函数来自定义行为,比如优雅退出、资源清理等。
使用 signal() 设置简单信号处理器
最基础的方法是调用 std::signal() 注册一个处理函数:
立即学习“C++免费学习笔记(深入)”;
#include#include volatile std::sig_atomic_t stop_flag = 0; void signal_handler(int sig) { if (sig == SIGINT) { std::cout << "\nCaught SIGINT, shutting down...\n"; stop_flag = 1; // 安全地通知主循环 } } int main() { std::signal(SIGINT, signal_handler); while (!stop_flag) { // 主循环工作 } std::cout << "Program exited gracefully.\n"; return 0; }
注意:stop_flag 被声明为 std::sig_atomic_t 并加上 volatile,确保在信号处理函数和主程序之间读写安全。
使用 sigaction 实现更安全可靠的信号处理
相比 signal(),sigaction() 提供更精确的控制,避免某些平台上的不一致行为:
#include#include #include volatile std::sig_atomic_t exit_requested = 0; void safe_signal_handler(int sig) { if (sig == SIGINT) { exit_requested = 1; } } int main() { struct sigaction sa; sa.sa_handler = safe_signal_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; // 自动重启被中断的系统调用 if (sigaction(SIGINT, &sa, nullptr) == -1) { std::cerr << "Failed to set signal handler\n"; return 1; } while (!exit_requested) { // 正常运行逻辑 } std::cout << "Cleanup and exit.\n"; return 0; }
这种方式避免了 signal() 在不同系统中的语义差异,更适合生产环境。
信号处理中的注意事项与安全规则
信号处理函数运行在异步上下文中,因此必须遵守以下限制:
- 只能调用异步信号安全函数(如 write(), _exit()),不能使用 cout、malloc、printf 等
- 避免在信号处理函数中执行复杂逻辑,仅设置标志位或使用 self-pipe trick
- 不要在信号处理中抛出异常或调用 longjmp(除非明确支持)
- 多线程环境下,信号通常由特定线程接收,建议屏蔽信号并在专用线程中通过 sigwait 处理
对于多线程程序,推荐使用 pthread_sigmask 屏蔽信号,再创建专门线程调用 sigwait 来同步处理,避免异步信号带来的竞态问题。
基本上就这些。合理使用信号机制可以让C++程序对外部中断做出快速而安全的反应,关键在于最小化信号处理函数的操作,只做状态标记,把实际处理逻辑留在主流程中执行。











