Как читать несколько файловых дескрипторов с помощью epoll select with 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.
Представьте себе, что у нас есть два fds: первый пассивный, данные доступны только иногда, второй активный, данные только иногда недоступны.
Epoll_wait возвратил, что мы можем прочитать оба. Мы читаем { первое, чем второе } в цикле (без вызовов epoll_wait, потому что это может внезапно заблокировать, пока данные еще доступны).
Теперь первый файловый дескриптор возвращает EAGAIN при чтении.
Что делать?
- Если мы пойдем дальше читая второй fd в цикле (без вызовов epoll_wait), мы можем пропустить, что данные стали доступны на первом fd. Он будет просто читать, читать и читать без ИГЕЙНА.
- Если мы будем "консультироваться" с epoll_wait перед каждым чтением из второго fd, epoll_wait может внезапно заблокировать из-за того, что ничего не изменилось с предыдущего вызова (данные все еще не доступны на первом FD и все еще доступны на втором FD).
Как продолжить обработку второго FD, но не забывая о первом FD?
Update: нашел еще одну вещь: man epoll_wait:
while specifying timeout equal to zero makes epoll_wait() to return immediately even if no events are available
С помощью этого я могу перечислять события для FDs, даже если их нет.
1 ответ:
Если FD2 постоянно читается, вы можете подумать, что epoll не подходит для него. Может быть, стоит спустить нитку,чтобы просто сидеть и читать.
В противном случае считывайте FD2 в цикле, пока он не будет слит, но в цикле пусть он попытается прочитать FD1 один раз через каждые X раз. Если у FD1 есть данные, считайте их. Если нет, вы просто получите EAGAIN, сбросьте счетчик X и вернитесь к чтению FD2. Когда оба будут опустошены, вы вернетесь в epoll_wait.
Что-то вроде:
count = 1; while (true) { read fd2; if (EAGAIN) break; else process data; count--; if (! count) { while (true) { read fd1; if (EAGAIN) count = 10; break; else process data; } } }