Пример типичной системно-прикладной разработки, реализация своей «очереди сообщений» (event loop).
Использованием
#epoll, вместо «традиционных» select & poll, для асинхронной работы через polling’а (и мультиплексирования).

Отслеживание файловых дескрипторов через
#epoll выглядит более современно, меньше копирования памяти между user space и kernel space. А при появлении ожидаемых данных можно напрямую переходить к объекту или структуре данных, что важно при наблюдении за несколькими файлами и\или соединениями. Устраняется поиск «сработавшего» файлового дескриптора в индексных массивах, полноценное О(1) во всех случаях. Можно сразу же работать с теми экземплярами объектов, которые оборачивают тот файл или udp-поток, tcp-, quic-соединение, где появились новые данные.

Есть несколько готовых к использованию «очередей сообщений» (event loop'ов) —
#libev, #libuv, #libevent. Для некоторых агент-серверные решений и брокера #RabbitMQ это подходит. Однако, в некоторых случаях AMQP-библиотеки не скрещиваются с уже готовыми «очередями сообщений». Потому что агентская часть может активно использовать асинхронно-реактивное программирование с хорошей и проверенной «горизонтальной масштабируемостью». Т.е. на агентской части выполняется много работы и реализация сделана через sharing nothing многопоточность. Это такая парадигма, когда не просто достигается не только горизонтальная масштабируемость через lock-free\wait-free, а так же исключается много вредного, как тот же cache ping-pong или false sharing. Внутри агентов идёт своё управление потоками с выделениями памяти. Не только в плане «динамической памяти» (heap, аллокаторы а-ля #jemalloc от #Facebook), но и приколами вокруг pinning страниц, учёта #NUMA и даже huge pages(меньше промахов в #TLB).

Почему бы не использовать epoll?
Библиотека не обязана вычитывает данные целиком из потока (сокета), а может забирает данные лишь до тех пор, пока не насытится автомат состояний (finite-state machine). Например, выполняется парсинг сущностей AMQP-протокола, которые, по мере накопления, передаются в обработчики указанные клиентом библиотеки.
И это плохо соотносится с тем, что используя
#epoll надо выбирать какой вариант оповещений использовать:
• «по уровню» (level-triggered),
• «по фронту» (edge-triggered).

Особенности поведения отдельно взятой библиотеки может не позволять использовать работу «по фронту» (edge-triggered), т.к. библиотека не вычитывает полностью все данные из файловых дескрипторов.

Можно быть хоть пять раз technical lead и всё это прекрасно знать, но следует помнить, что как только в коде появляется флаг EPOLLET, то необходимо проводить аудит работы с потоками данных. Это избавляет команду от многих заморочек вокруг тестирования и ковыряния с каким-то совершенно непонятным поведением кода.

Про
«Edge Triggered Vs Level Triggered interrupts»

#programming #linux #softdev #трудовыебудни
Edge Triggered Vs Level Triggered interrupts

Discussion: Level triggered: as long as the IRQ line is asserted, you get an interrupt request. When you serve the interrupt and return, ...

Пересказ уже упомянутого примера, чем приходится порой заниматься в сфере разработки софта и распределённых решений. Что далеко не всё уже написано, далеко не всё удаётся слепить из уже готовых кубиков, якобы не парясь и побыстрее выпихивая в продакшен :)