使用带0超时的poll()检测文件描述符是否阻塞的方案是否合理?
代码存在的几个遗漏问题
- 没有处理poll调用出错的场景
你当前的逻辑只判断了poll返回值是否为0,完全忽略了返回-1的错误情况:比如传入的fd本身无效、调用过程被系统信号中断等场景下,poll会返回-1,此时你的函数会直接返回0,错误认为当前操作会阻塞,实际是调用本身出了问题。建议补充错误分支,把错误返回给上层调用方处理。 - 没有校验文件描述符的异常状态
poll的特性是就算你没有在events字段注册POLLERR/POLLNVAL/POLLHUP这类异常事件,只要对应fd触发了这些异常(比如fd已经被关闭、连接已经断开),poll就会自动在revents里带上这些事件并返回正数。此时你按照现有逻辑会认为fd可用,但实际执行读写操作依然会报错。建议补充对revents字段的校验,排除异常场景。
修复后的参考代码如下:
int wouldblock(int fd, short event) { struct pollfd pfd; pfd.fd = fd; pfd.events = event; int ret = poll(&pfd, 1, 0); if (ret < 0) return ret; // 调用出错,返回错误码给上层处理 if (ret == 0) return 1; // 超时无事件,确实会阻塞 // 检查是否触发了异常事件 if (pfd.revents & (POLLERR | POLLNVAL | POLLHUP)) { return -1; // fd状态异常,交给上层判断如何处理 } return 0; // 对应事件就绪,不会阻塞 }
关于是否属于过度设计、有没有系统负担
完全不用担心这个问题:
- 超时设为0的poll只是触发内核快速查询fd的状态,不会进入睡眠调度,全程只是一次很轻量的用户态到内核态的调用,单fd的场景下开销极低,完全不会给系统带来额外负担。
- 对比同类实现方案(比如用fcntl反复修改fd的O_NONBLOCK属性,试读写之后再改回原有属性),用poll的方案开销反而更小,逻辑也更清晰,也不会修改fd本身的配置,是非常标准的实现方式,很多开源项目里都有类似的封装,完全可以放心使用。
内容的提问来源于stack exchange,提问作者Remo.D
相关产品推荐
相关产品推荐

