C++ 信号处理基础
信号是操作系统用于通知进程发生某种事件的机制,例如用户按下Ctrl+C(SIGINT)或程序访问非法内存(SIGSEGV)。C++ 通过<csignal>头文件提供信号处理支持。
常用信号类型
SIGINT:终端中断(如Ctrl+C)。SIGSEGV:非法内存访问。SIGTERM:终止请求(如kill命令)。SIGALRM:定时器超时(alarm()触发)。
注册信号处理函数
使用signal()或更安全的sigaction()注册信号处理函数:
#include <csignal> #include <iostream> void handler(int signal) { std::cout << "Received signal: " << signal << std::endl; } int main() { signal(SIGINT, handler); // 注册 SIGINT 处理函数 while (true) {} // 模拟长时间运行 return 0; }使用sigaction增强控制
sigaction提供更细粒度的信号控制(如屏蔽其他信号):
#include <csignal> #include <iostream> void handler(int signal) { std::cout << "Safe handling of signal: " << signal << std::endl; } int main() { struct sigaction sa; sa.sa_handler = handler; sigemptyset(&sa.sa_mask); // 不屏蔽其他信号 sa.sa_flags = 0; sigaction(SIGINT, &sa, nullptr); // 替换 signal() while (true) {} return 0; }发送信号
使用kill()或raise()发送信号:
#include <csignal> #include <unistd.h> int main() { raise(SIGINT); // 向自身发送 SIGINT kill(getpid(), SIGTERM); // 等效于 raise(SIGTERM) return 0; }信号与多线程
在多线程程序中,信号的处理需谨慎:
- 信号可能被任意线程捕获。
- 使用
pthread_sigmask()控制线程的信号屏蔽。
#include <pthread.h> #include <csignal> void* thread_func(void*) { sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); pthread_sigmask(SIG_BLOCK, &mask, nullptr); // 屏蔽 SIGINT while (true) {} return nullptr; }异步信号安全
信号处理函数中只能调用异步信号安全函数(如write(),避免cout或malloc):
#include <unistd.h> #include <csignal> void handler(int) { write(STDOUT_FILENO, "Signal!\n", 8); // 安全 }定时信号示例
使用alarm()和SIGALRM实现定时器:
#include <unistd.h> #include <csignal> #include <iostream> void alarm_handler(int) { std::cout << "Alarm triggered!" << std::endl; } int main() { signal(SIGALRM, alarm_handler); alarm(2); // 2 秒后触发 SIGALRM pause(); // 等待信号 return 0; }注意事项
- 避免在信号处理函数中执行复杂操作。
- 多线程程序优先使用线程同步机制而非信号。
sigaction比signal更可控,推荐使用。