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)在信号处理程序中尽量减少工作
信号处理程序中应该执行最少的必要工作,例如设置标志或写入小的固定消息,然后迅速返回。任何复杂操作都应交给主程序处理。