2017-02-15 11 views
2

У меня есть следующие требования к механизму IPC на Linux:Broadcast IPC на Linux

  1. Существует единый процесс производителя, но несколько процессов потребления. Потребительские процессы - это не дети производственного процесса. Они воспитываются независимо.

  2. Передаваемые сообщения представляют собой структуры POD фиксированного размера.

  3. Мы должны использовать фиксированный объем памяти для этого механизма. Кольцевой буферный механизм кажется идеальным здесь.

  4. Производитель должен работать очень быстро и никогда не сможет дождаться потребителей. Вместо этого ему необходимо перезаписать записи в буфере фиксированного размера (для IPC), и потребители должны обнаружить эту проблему и просто догнать производителя, пропуская промежуточные сообщения в случае обертывания.

  5. Потребители могут прийти и уйти в любое время, и не должно быть явного рукопожатия между единственным производителем и эфемерными потребителями по мере их появления и ухода. Поэтому, когда потребители приходят, они просто начинают читать из последнего доступного сообщения и уходят, когда захотят, без того, чтобы производители знали.

У меня есть следующее решение прямо сейчас:

  1. я создаю кольцевой буфер записей фиксированного размера, которые записываются одним процессом и читать многие. Кольцевой буфер построен поверх файла с отображением памяти в/tmp.

  2. Код буфера звонка таков, что производители никогда не блокируют ожидание того, что любой из потребителей будет потреблять записи. Вместо этого потребители обнаруживают, когда кольцевой буфер обернут в середине чтения/обработки записи и просто догоняют до последнего. Я делаю это с несколькими последовательностями производителя. Я могу расширить это, если это необходимо, но не кажется очень актуальным. Таким образом, производители галопом на полной скорости и потребители, которые отстают, обнаруживают, что в середине считывают коррупцию и пропускают последнюю запись.

На данный момент это работает нормально. Теперь я пытаюсь понять, как добавить некоторую сигнализацию в микс, чтобы потребители не вынуждены были читать последовательности продюсеров, ожидая появления нового сообщения. У меня есть дополнительные требования к сигнальной части:

  1. Передача сигналов должна быть своего рода механизмом вещания. Это следует из требования одного производителя/multiple_consumers. Поэтому многие процессы должны быть разбужены, когда производители сигнализируют о них. Учитывая, что производитель не знает ни о каком из потребителей, похоже, нам нужен какой-то именованный ресурс для этой сигнализации.

  2. Механизм сигнализации должен быть совместим с другими регулярными сигналами, которые можно ожидать при использовании select/epoll_wait. Потребители, которые читают этот механизм IPC/ring_buffer, ждут при записи в другие несвязанные каналы/сокеты и т. Д., И они используют выбор в этих FD. Было бы идеально, чтобы иметь возможность просто создавать FD из этого механизма, который потребители могли бы просто добавить к своему избранному вызову. Аналогично, если потребитель ждет на нескольких таких ring_buffers, мы должны иметь возможность блокировать их все и просыпаться, как только кто-либо из них сигнализирует.

С учетом этих требований устранил несколько вариантов:

  1. переменные условия: Мы не можем блокировать на нескольких из них от потребителя. Они также не selectable.

  2. Именованные трубы: нам понадобится именованная труба для каждого потребителя, и это подразумевает какое-то поручение производителя/потребителя, которого мы хотим избежать.

  3. eventfd: eventfds не названы, поэтому кажется, что они являются лишь решением, если сигнализация находится между родительскими и дочерними процессами. В моем сценарии есть процессы, которые запускаются независимо.

  4. Unix доменное сокет: здесь, похоже, нет какого-либо средства вещания, поэтому я не уверен, что это будет работать без явного сокета для каждого потребителя. Это противоречит требованию об отсутствии квитирования.

Я нахожусь в убытке и не вижу другого хорошего варианта. Для меня, похоже, будет работать многоадресная рассылка UDP. Все потребители могут быть частью многоадресной группы (создать сокет с SO_REUSEADDR), и единственный производитель может отправлять сообщения в эту группу, чтобы сигнализировать потребителям. Но это кажется действительно тяжелым и сложным. Есть ли другие хорошие механизмы, чтобы это произошло? Я готов работать непосредственно с Futex API, если это помогает, если оно составлено с блокировкой на других несвязанных FD с использованием select/epoll.

ответ

1

Я рекомендую отправить сигнал через DBus. Зачем откатывать свой собственный IPC, когда вы можете использовать зрелую фреймворк, которая уже делает то, что вы хотите?

Эта страница поможет вам начать:

https://dbus.freedesktop.org/doc/dbus-tutorial.html

В конце концов, она включает в себя ссылку на Qt и GLib API. Я не использовал ни одного из них, вместо этого писал свою собственную оболочку на основе Boost.ASIO вокруг низкоуровневого API, хотя это довольно сложное мероприятие.

https://dbus.freedesktop.org/doc/api/html/

Кстати, для отправки блоков двоичных данных, вы хотите добавить в ARG типа DBUS_TYPE_ARRAY из DBUS_TYPE_BYTE, к вашему сообщению. Обратите внимание: DBUS_TYPE_STRING не может содержать нулевые байты или недействительные последовательности юникода.

Обновление: Еще одна недавно открывшаяся мне библиотека называется sd-bus. Вот хороший обзор & учебник:

http://0pointer.net/blog/the-new-sd-bus-api-of-systemd.html