Я предполагаю, что ситуация, которую вы пытаетесь обработать, выглядит примерно так:
У вас есть несколько (может быть, очень много) сокетов, из которых вы хотите получать данные одновременно;
Вы хотите начать обработку данных с первого соединения в потоке A при его первом получении, а затем убедитесь, что данные из этого соединения не обрабатываются ни в одном другом потоке, пока вы не закончили с ним в потоке A.
Пока вы это делаете, если некоторые данные теперь получены по другому соединению, вы хотите, чтобы поток B выбрал эти данные и обработал их, при этом все еще будучи уверенным, что никто не сможет обработать это соединение, пока поток B не завершит его и т. Д. .
В этих обстоятельствах оказывается, что использование epoll_wait () с одним и тем же epoll fd в нескольких потоках является достаточно эффективным подходом (я не утверждаю, что он обязательно является наиболее эффективным).
Хитрость в том, чтобы добавить отдельные соединения fds в epoll fd с флагом EPOLLONESHOT. Это гарантирует, что как только fd был возвращен из epoll_wait (), он не контролируется, пока вы специально не скажете epoll, чтобы отслеживать его снова. Это гарантирует, что поток, обрабатывающий это соединение, не подвергается никаким помехам, поскольку никакой другой поток не может обрабатывать это соединение, пока этот поток не помечает соединение, подлежащее мониторингу.
Вы можете настроить fd для отслеживания EPOLLIN или EPOLLOUT снова, используя epoll_ctl () и EPOLL_CTL_MOD.
Существенным преимуществом использования epoll, подобного этому, в нескольких потоках является то, что, когда один поток завершает соединение и добавляет его обратно в контролируемый набор epoll, все остальные потоки, все еще находящиеся в epoll_wait (), немедленно отслеживают его даже до предыдущего поток обработки возвращается к epoll_wait (). Между прочим, это также может быть недостатком из-за отсутствия локальности данных кэша, если другой поток теперь немедленно обнаруживает это соединение (таким образом, необходимо извлечь структуры данных для этого соединения и очистить кэш предыдущего потока). Что работает лучше всего, будет зависеть от вашего точного шаблона использования.
Если вы пытаетесь обрабатывать сообщения, полученные впоследствии по одному и тому же соединению в разных потоках, тогда эта схема использования epoll вам не подойдет, и подход с использованием прослушивающего потока, питающего эффективную очередь, питающую рабочие потоки, может быть лучше.