第 50 / 120 课 · 并发、IPC 与异步 I/O。返回课程合集。
机制与资源关系
就绪通知表示当前操作有机会不阻塞,并不保证完整消息到达。epoll 的 LT 与 ET 对事件处理方式不同;ET 常配合非阻塞 I/O,读写到 EAGAIN,否则可能留下未处理数据。
实际用法与观察入口
以下是操作说明;先确认执行环境、工具帮助和目标对象。设备名、PID、地址及项目名示例需要按实际替换,不能将整段命令当通用板端脚本执行。
|
输出解读与排查顺序
设计超时和错误事件处理,区分 POLLIN、POLLHUP、POLLERR。多个消费者会改变就绪状态;收到事件后仍需检查系统调用结果。select 还受 fd 集合表示能力约束。
情境推演
epoll ET 收到一次通知后只读一个字节,剩余数据可能没有新的边沿通知。正确设计常要求非阻塞循环读到 EAGAIN,并对每次返回值与连接关闭分别处理。
练习与参考分析
先 poll 空管道得到超时,再写入并获得就绪。参考结论:有超时不是业务成功,必须继续判断返回事件和实际读取字节数。
独立实验包
主机 Linux 的有界 C 实验;不访问真实外设,不代表板端时序或性能。 默认入口、源文件和实际运行记录都在下载包中。
实验:select、poll 与 epoll
查看完整代码:main.c
int main(void) {
int p[2]; CHECK(pipe(p) == 0);
struct pollfd watch = {.fd=p[0], .events=POLLIN};
CHECK(poll(&watch, 1, 0) == 0);
CHECK(write(p[1], "x", 1) == 1);
CHECK(poll(&watch, 1, 1000) == 1 && (watch.revents & POLLIN));
char c=0; CHECK(read(p[0], &c, 1) == 1 && c == 'x');
CHECK(close(p[0]) == 0); CHECK(close(p[1]) == 0);
puts("empty poll=timeout; after write=POLLIN; consumed x");
return 0;
}
在项目根目录执行;下载包解压后,在解压目录执行 sh run.sh。
cd 'content/posts/驱动、bootloader、文件系统/嵌入式Linux系统工程/050-select、poll 与 epoll/code' && sh run.sh
官方资料与版本边界
内核、工具和厂商 BSP 的支持范围需分别核对。参考资料可能对应较新版本;不要据此推定旧 BSP 支持所有接口。