fgets()读取/sys/bus/temp1_input时阻塞卡死,求助排查原因
问题分析与解决方案
你的问题核心是**/sys虚拟文件系统的特殊性**导致的fgets阻塞,而非单纯的文件开关操作。以下是具体原因和解决办法:
可能的原因
- /sys文件的内核驱动逻辑:/sys下的文件并非磁盘真实文件,每次读取都会触发内核驱动去采集传感器数据。如果传感器驱动在多次读取后出现资源锁、死循环或响应滞后,就会导致用户态的fgets因等待内核返回数据而卡住。而
cat命令的读取逻辑(比如一次性读取整个文件、不同的系统调用组合)可能绕过了驱动的异常状态,或者内核在处理cat的请求时重新恢复了响应。 - stdio缓冲的干扰:fgets属于stdio库函数,自带用户态缓冲。当与/sys这类动态生成内容的虚拟文件交互时,缓冲机制可能导致数据同步异常,进而引发阻塞。
解决办法
1. 改用系统调用直接读取(绕过stdio缓冲)
替换fopen/fgets为open/read/close,避免stdio的缓冲逻辑干扰:
// 替换原代码的读取逻辑 int fd = open("/sys/bus/temp1_input", O_RDONLY); if (fd != -1) { char val_str[10]; // 读取数据,预留空间给结束符 ssize_t bytes_read = read(fd, val_str, sizeof(val_str) - 1); if (bytes_read > 0) { val_str[bytes_read] = '\0'; // 手动添加字符串结束符 temp_val = atoi(val_str); } close(fd); }
2. 保持文件句柄长期打开,避免频繁开关
/sys文件打开后,每次读取都会重新触发数据采集,无需反复关闭再打开。长期持有句柄可以减少驱动层面的资源申请/释放操作,降低异常概率:
// 程序初始化阶段打开一次文件 int fd = open("/sys/bus/temp1_input", O_RDONLY); if (fd == -1) { // 处理打开失败的逻辑,比如打印错误 perror("open temp1_input failed"); } // 每次扫描时的操作 if (fd != -1) { // 移动文件指针到开头 lseek(fd, 0, SEEK_SET); char val_str[10]; ssize_t bytes_read = read(fd, val_str, sizeof(val_str) - 1); if (bytes_read > 0) { val_str[bytes_read] = '\0'; temp_val = atoi(val_str); } } // 程序退出前关闭文件 if (fd != -1) { close(fd); }
3. 排查内核驱动状态
如果上述方法仍无效,通过dmesg命令查看内核日志,检查是否有温度传感器驱动的错误信息(比如资源死锁、硬件异常),这可能需要驱动层面的修复。
关于非阻塞模式的说明
给open添加O_NONBLOCK标志可以让read不会阻塞,但这只是避免程序卡住,无法解决驱动层面的异常。此时read会返回-1并设置errno为EAGAIN,你需要处理这种情况并考虑重试策略,但这并非根本解决方案。
内容的提问来源于stack exchange,提问作者Easha Jilakar
相关产品推荐
相关产品推荐

