Я пишу небольшой сервер, который будет получать данные из нескольких источников и обрабатывать эти данные. Источники и полученные данные значительны, но не более чем epoll должен уметь справляться достаточно хорошо. Однако все полученные данные необходимо проанализировать и запустить через большое количество тестов, что отнимает много времени и блокирует один поток, несмотря на мультиплексирование epoll. По сути, шаблон должен быть примерно таким: цикл ввода-вывода получает данные и объединяет их в задание, отправляет их первому потоку, доступному в пуле, пакет обрабатывается заданием, и результат передается пакетом в цикл ввода-вывода для запись в файл.
Я решил использовать один поток ввода-вывода и N рабочих потоков. Поток ввода-вывода для приема TCP-соединений и чтения данных легко реализовать, используя пример, представленный по адресу: http://linux.die.net/man/7/epoll
С потоками также обычно достаточно легко справиться, но я изо всех сил пытаюсь элегантно объединить цикл ввода-вывода epoll с пулом потоков. Я также не могу найти никаких "лучших практик" для использования epoll с рабочим пулом в Интернете, но есть довольно много вопросов по той же теме.
Поэтому у меня есть вопрос, и я надеюсь, что кто-нибудь поможет мне ответить:
- Можно (и нужно) использовать eventfd как механизм для двусторонней синхронизации между потоком ввода-вывода и всеми рабочими? Например, неплохо ли для каждого рабочего потока иметь свою собственную процедуру epoll, ожидающую совместного использования eventfd (с указателем структуры, содержащим данные / информацию о задании), то есть каким-то образом использовать eventfd в качестве очереди заданий? Также, возможно, есть еще один eventfd для передачи результатов обратно в поток ввода-вывода из нескольких рабочих потоков?
- После того, как поток ввода-вывода получает сигнал о большем количестве данных в сокете, должно ли происходить фактическое получение данных в потоке ввода-вывода или рабочий должен получать данные самостоятельно, чтобы не блокировать поток ввода-вывода при анализе фреймов данных и т. Д.? В таком случае, как я могу обеспечить безопасность, например в случае, если recv читает 1,5 кадра данных в рабочем потоке, а другой рабочий поток получает последние 0,5 кадра данных из того же соединения?
- Если пул рабочих потоков реализован через мьютексы и тому подобное, будет ли ожидание блокировок блокировать поток ввода-вывода, если N + 1 потоки пытаются использовать одну и ту же блокировку?
- Существуют ли какие-либо образцы хорошей практики для создания пула рабочих потоков вокруг epoll с двусторонней связью (т.е. как от ввода-вывода к рабочим, так и обратно)?
РЕДАКТИРОВАТЬ: одним из возможных решений может быть обновление кольцевого буфера из цикла ввода-вывода, после обновления отправить индекс кольцевого буфера рабочим через общий канал для всех рабочих (тем самым передав контроль над этим индексом первому рабочему, который читает index от канала), пусть рабочий владеет этим индексом до конца обработки, а затем снова отправит номер индекса обратно в поток ввода-вывода через канал, тем самым вернув управление?
Мое приложение предназначено только для Linux, поэтому я могу использовать функции только для Linux, чтобы добиться этого наиболее элегантным способом. Кросс-платформенная поддержка не нужна, но требуется производительность и безопасность потоков.