名称
epoll - I/O 事件通知工具
概要
#include <sys/epoll.h>
描述
epoll API 提供了与 poll 类似的机制:监控多个文件描述符中的任意一个是否 I/O 就绪。epoll API 可以使用边缘触发 (edge-triggered) 或者水平触发 (level-triggered) 接口,可以很好地监控大量的文件描述符。以下的系统调用可以提供创建和管理 epoll 实例:
- epoll_create() 创建一个 epoll 实例并返回一个关联实例的文件描述符。
- 通过 epoll_ctl() 注册感兴趣的文件描述符。当前在 epoll 实例上注册的文件描述符通常也称之为 epoll 集。
- epoll_wait() 等待 I/O 事件,如果当前没有事件发生则一直阻塞调用线程。
水平触发和边缘触发
epoll 事件分布接口可以表现为边缘触发 edge-triggered (ET) 和水平触发 level-triggered (LT)。这两种模式的主要区别描述如下,假设以下的场景:
- 一个管道的读端的文件描述符 (rfd) 注册到了 epoll 实例。
- 在管道的写端写入 2 kB 数据。
- 调用 epoll_wait() 完成之后将 rfd 作为准备好的文件描述符返回。
- 从管道的读端读取了 1 kB 数据。
- epoll_wait() 调用结束。
如果 rfd 文件描述符使用 EPOLLET (edge-triggered) 标志加入到 epoll 实例,那么在第 5 步调用 epoll_wait() 时将会被挂起,尽管缓冲区内仍然有可读数据;同时,管道的另一端可能正在等待一个回复,因为它已经发送了数据。产生这种情况的原因是因为边缘触发模式仅在所监控的文件描述符发生变化时才会触发事件。所以,调用者可能需要在第 5 步的时候一直等待一些数据传送到缓冲区。在以上的例子中,产生 rfd 事件是因为第 2 步有一个写事件已经完成,这个事件激活了第 3 步。又因为第 4 步的操作未完全消费掉整个缓冲区数据,所以对 epoll_wait() 的调用可能会在第 5 步无限期阻塞下去。