C语言代码实现
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
volatile sig_atomic_t flag = 0;
void signal_handler(int signum) {
if (signum == SIGINT || signum == SIGTERM) {
flag = 1;
printf("Received signal %d, preparing to exit gracefully...\n", signum);
}
}
int main() {
// 注册信号处理函数
if (signal(SIGINT, signal_handler) == SIG_ERR) {
perror("signal(SIGINT)");
return 1;
}
if (signal(SIGTERM, signal_handler) == SIG_ERR) {
perror("signal(SIGTERM)");
return 1;
}
printf("Process is running. Press Ctrl+C to stop.\n");
while (!flag) {
// 主程序逻辑
printf("Working...\n");
sleep(1);
}
// 进行资源清理等操作
printf("Cleaning up resources...\n");
// 假设这里有资源清理的代码
printf("Exiting gracefully.\n");
return 0;
}
信号处理函数与主程序逻辑的交互
- 注册信号处理函数:使用
signal
函数为SIGINT
和SIGTERM
信号注册处理函数signal_handler
。当这些信号到达时,系统会暂停主程序的执行,跳转到信号处理函数执行。
- 标志位的使用:在信号处理函数中设置一个全局的
volatile sig_atomic_t
类型的标志位flag
。这样主程序在循环中可以通过检查这个标志位来决定是否退出,从而实现了信号处理函数与主程序逻辑的通信。
- 主程序逻辑:主程序在
while (!flag)
循环中执行正常的业务逻辑。当flag
被信号处理函数设置后,循环结束,主程序可以进行资源清理等收尾工作后退出。
可能遇到的竞态条件及解决方法
- 竞态条件:在多线程环境或者信号处理与主程序逻辑共享资源时,可能会出现竞态条件。例如,如果主程序正在读取或修改某个共享资源时,信号处理函数被触发,也对该资源进行操作,就可能导致数据不一致。
- 解决方法:
- 使用互斥锁:在多线程环境下,使用互斥锁(如
pthread_mutex_t
)来保护共享资源。在访问共享资源前加锁,访问结束后解锁。
- 异步信号安全函数:在信号处理函数中,只调用异步信号安全的函数。例如,
printf
在信号处理函数中使用可能不安全,应该使用write
函数代替。
- 使用标志位和同步机制:如上述代码中,通过设置标志位来通知主程序进行资源清理,而不是在信号处理函数中直接进行复杂的资源清理操作,避免了在信号处理函数中访问共享资源带来的竞态问题。