如何使用 epoll_select 和 EPOLLET 读取多个文件描述符?
man epoll:
The suggested way to use epoll as an edge-triggered (EPOLLET) interface is as follows:
i with nonblocking file descriptors; and
ii by waiting for an event only after read(2) or write(2) return EAGAIN.
假设我们有两个 fd:第一个是被动的,数据仅有时可用,第二个是主动的,数据仅有时不可用。
epoll_wait 返回我们可以读取两者。我们在循环中读取{第一个,而不是第二个}(没有调用epoll_wait,因为它可能会在数据仍然可用时突然阻塞)。
现在,第一个文件描述符在读取时返回 EAGAIN。
该怎么办?
- 如果我们继续循环读取第二个 fd(不调用 epoll_wait),我们可能会错过第一个 fd 上的数据已变得可用。它只会读啊读啊读,而无需 EAGAIN。
- 如果我们在每次从第二个 fd 读取之前“咨询”epoll_wait,epoll_wait 可能会突然阻塞,因为上次调用没有任何变化(数据在第一个 FD 上仍然不可用,但在第二个 FD 上仍然可用)。
如何继续处理第二个 FD,但又不忘记第一个 FD?
更新:又发现了一件事:man epoll_wait:
while specifying timeout equal to zero makes epoll_wait() to return immediately even if no events are available
有了这个,即使没有事件,我也可以枚举 FD 的事件。
man epoll:
The suggested way to use epoll as an edge-triggered (EPOLLET) interface is as follows:
i with nonblocking file descriptors; and
ii by waiting for an event only after read(2) or write(2) return EAGAIN.
Imagine we have two fds: the first is passive, data available only sometimes, the second is active, data only sometimes not available.
epoll_wait returned that we can read both. We read { the first, than the second } in a loop (without calls to epoll_wait because of it may suddenly block while the data is still available).
Now the first file descriptor returned EAGAIN on read.
What to do?
- If we go on reading the second fd in a loop (without calls to epoll_wait), we can miss that the data have become available on the first fd. It will just read and read and read without EAGAIN.
- If we will "consult" with epoll_wait before each read from the second fd, epoll_wait may SUDDENLY block because of nothing changed from the previous call (data still not available on the first FD and still available on the second FD).
How to continue processing of the second FD, but without forgetting about the first FD?
Update: Found one more thing: man epoll_wait:
while specifying timeout equal to zero makes epoll_wait() to return immediately even if no events are available
With this I can enumerate events for FDs even if there are no events.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果 FD2 始终可读,您可能会认为 epoll 不适合它。或许值得抽出一条线索来坐下来阅读它。
否则,在循环中读取 FD2,直到其耗尽,但在循环中尝试每 X 次读取 FD1 一次。如果FD1有数据,则读取它。如果没有,您将得到 EAGAIN,重置 X 计数器并返回读取 FD2。当两者都耗尽时,您将回到 epoll_wait。
像这样的东西:
If FD2 is constantly readable you might consider that epoll is not appropriate for it. It might be worth spinning off a thread just to sit and read it.
Otherwise, read FD2 in a loop until it is drained but in the loop have it attempt to read FD1 once every X times through. If FD1 has data, read it. If not you'll just get EAGAIN, reset the X counter and go back to reading FD2. When both are drained you are back to epoll_wait.
Something like: