使用poll()结合POLLIN等待文件变化时触发无限循环的问题
解决poll()监听sysfs文件时POLLIN无限触发的问题
问题原因
- 普通文件的poll行为:普通文件的
poll()实现会始终返回POLLIN,因为系统认为普通文件随时可读取(无论内容是否变化),所以用普通文件测试内核通知场景本身不适用。 - sysfs文件读取不彻底:你的代码仅调用一次
read(),若未读到EOF(比如缓冲区buf小于属性内容,或未消费完所有数据),poll()会判定仍有数据可读,从而持续触发POLLIN。
修复方案
针对sysfs文件的正确处理方式:
- 读取到EOF:每次
poll()触发POLLIN后,循环调用read()直到返回0(EOF),确保彻底读取当前属性内容,这样下次poll()才会等待内核sysfs_notify()的通知。 - 适配sysfs特性:sysfs属性更新会通过
sysfs_notify()唤醒等待的poll(),但只有读完所有当前内容后,才会进入等待状态。
修改后的代码示例:
... struct pollfd *fds = malloc(sizeof(struct pollfd) * 1); char buf[256]; ssize_t ret; fds[0].fd = open("/path/to/sysfs-file", O_RDONLY); if (fds[0].fd < 0) { free(fds); return -EXIT_FAILURE; } fds[0].events = POLLIN; fds[0].revents = 0; while (poll(fds, 1, -1) > 0) { if (fds[0].revents & POLLIN) { fds[0].revents = 0; // 循环读取直到EOF,确保清空所有可读数据 while ((ret = read(fds[0].fd, buf, sizeof(buf))) > 0) { // 处理读取到的数据,如打印或解析 // printf("Read: %.*s", (int)ret, buf); } // 处理read错误(排除中断信号) if (ret == -1 && errno != EINTR) { perror("read failed"); break; } } } close(fds[0].fd); free(fds); ...
额外说明
- 不要用普通文件测试sysfs的
poll()通知逻辑,普通文件不支持内核主动触发的通知机制,poll()持续返回POLLIN是预期行为。 - 部分sysfs属性会使用
POLLPRI事件,可尝试监听POLLIN | POLLPRI,读取后用lseek(fd, 0, SEEK_SET)重置文件指针,但大部分场景下,读取到EOF即可解决问题。
内容的提问来源于stack exchange,提问作者Anton Kalistratov
相关产品推荐
相关产品推荐

