1、要避免在信号处理程序中使用 printf的原因
许多C标准库函数(例如 printf
)不是重入的。这意味着它们可能依赖共享状态(例如全局或静态变量)。如果在信号处理程序中中断了这些函数的执行,可能会导致未定义行为。信号处理程序中调用的函数必须是异步信号安全的。像 printf
这样的函数可能会分配内存、加锁或使用其他资源,这些在信号处理上下文中可能不安全。
2、避免在信号处理程序中使用 printf 的常见方法
1) 使用 write 替代 printf
write
系统调用是异步信号安全的,可以直接输出到文件描述符(例如 STDOUT_FILENO
)。
#include <stdio.h> #include <signal.h> #include <unistd.h> void signal_handler(int signum) { const char msg[] = "Signal received!\n"; write(STDOUT_FILENO, msg, sizeof(msg) - 1); // 使用 write 替代 printf } int main() { signal(SIGINT, signal_handler); while (1) { // 主程序循环 } return 0; }
2)设置标志位,让主程序处理输出
与其直接在信号处理程序中打印信息,不如设置一个标志位,让主程序负责打印。
#include <stdio.h> #include <signal.h> #include <stdbool.h> volatile sig_atomic_t signal_flag = 0; void signal_handler(int signum) { signal_flag = 1; // 设置标志位 } int main() { signal(SIGINT, signal_handler); while (1) { if (signal_flag) { printf("Signal received!\n"); signal_flag = 0; // 重置标志位 } } return 0; }
3)将日志写入文件描述符
可以使用 write
函数将日志直接写入文件描述符,而不是使用 printf
。
#include <signal.h> #include <unistd.h> #include <fcntl.h> void signal_handler(int signum) { const char msg[] = "Signal received!\n"; int fd = open("signal.log", O_WRONLY | O_CREAT | O_APPEND, 0644); if (fd >= 0) { write(fd, msg, sizeof(msg) - 1); close(fd); } } int main() { signal(SIGINT, signal_handler); while (1) { // 主程序循环 } return 0; }
4)在信号处理程序中尽量减少工作
信号处理程序中应该执行最少的必要工作,例如设置标志或写入小的固定消息,然后迅速返回。任何复杂操作都应交给主程序处理。