Как читать несколько файловых дескрипторов с помощью 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 при чтении.

Что делать?

  1. Если мы пойдем дальше читая второй fd в цикле (без вызовов epoll_wait), мы можем пропустить, что данные стали доступны на первом fd. Он будет просто читать, читать и читать без ИГЕЙНА.
  2. Если мы будем "консультироваться" с 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 2

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;
       }
   }
}