Как проснуться темы с ZeroMQ
Моя текущая программа получает сообщения через zmq. Поток просыпается время от времени и проверяет, что zmq получил последним.
Теперь я хочу улучшить эту настройку и фактически обрабатывать каждое входящее сообщение, а не только последнее при пробуждении. Также я хочу, чтобы моя тема просто проснулась, когда появилось что-то новое. Есть ли способ, как zmq может заставить мою нить проснуться, как только у него появится новое сообщение для моей нити.
2 ответа
Как вы упомянули "Также я хочу, чтобы мой поток просто просыпался, когда есть что-то новое. ", Это может быть достигнуто, если обратному вызову назначен прием данных, поэтому всякий раз, когда поступают новые данные, будет выполняться обратный вызов.
Но после прочтения про zeromq и ссылки на следующие ссылки:
Можно ли добавить обработку событий в ZeroMQ, чтобы действовать при получении / отправке данных?
Есть ли в ZeroMQ уведомление / событие обратного вызова / сообщение о поступлении данных?
Похоже, что на данный момент ZeroMQ не реализует никаких обратных вызовов, которые бы уведомляли нас при получении новых данных. Вы можете определенно проверить наличие новых данных, используя zmq_recv в режиме блокировки (но это не означает пробуждение при появлении новых данных, просто блокирование будет продолжаться до тех пор, пока данные не будут получены).
Одно из возможных решений, как указано в приведенных выше ссылках:
Вы можете использовать СИГНАЛЫ вместе с zmq, который будет уведомлять, когда поступают новые данные. Преимущество использования обработчика сигналов / обработчиков прерываний состоит в том, что они не будут блокировать ваш код, пока не поступят новые данные (например, zmq_recv()
в режиме блокировки), вместо этого обработчики сигнала будут активироваться и выполняться только при получении определенного сигнала.
Сигналы как SIGUSR1
/SIGUSR2
может использоваться как указание поступления новых данных. Назначьте обработчик сигнала SIGUSR1
выполнить код при поступлении новых данных.
Чтобы запустить процесс всякий раз, когда у вас есть новые данные, вам нужно будет отправить данные, а также отправить сигнал, например:
zmq_send(...);
kill(pid, SIGUSR1); /* Send signal SIGUSR1 to the process
whose PID is specified
*/
Процесс получения получает сигнал SIGUSR1
и просыпается, чтобы выполнить его обработчик. В обработчике этого сигнала вы можете прочитать данные и выполнить некоторую задачу. Теперь этот обработчик будет выполнен снова, только если вы отправите новые данные вместе с SIGUSR1
сигнал.
ZMQ - все о программировании модели актера. Это Реактор. Ты используешь zmq_poll()
ждать, пока один из наборов сокетов будет готов к чтению. Когда вы это делаете, вы читаете из него.
Таким образом, ваша программа становится циклом, в верхней части вы вызываете zmq_poll()
какие блоки (или тайм-ауты), и после этого вы имеете дело с тем, какой сокет стал готов к чтению, а затем зацикливается.
Напротив, обратные вызовы относятся к программированию модели Proactor. Вы говорите, что должно произойти заранее (настраивая обратный вызов), и тогда это произойдет, несмотря ни на что.
Важно помнить, что Reactor и Proactor действительно не смешиваются. Никогда не пытайтесь смешать их вместе, если вы можете помочь, это будет источником бесконечной путаницы. Либо пойти ва-банк с одним или другим. Вот почему ZeroMQ не имеет механизма обратного вызова.
Плохое смешение двух стилей является причиной того, что транспорт IPC для ZeroMQ не работает в Windows. Реактор ZeroMQ является zmq_poll()
, В основном это зависит от ОС, предоставляющей реактор. В Linux это select()
или же epoll()
который, как стандарт для *nix, может работать с любым дескриптором файла (сетевые сокеты, каналы IPC, последовательные порты и т. д.).
В отличие от Windows не предоставляет универсальный реактор. Ближайший это select()
, который работает только на сетевых сокетах. Чтобы заблокировать канал в Windows, вы используете вызовы, которые принимают обратные вызовы. По сути, Windows - это проакторная система, и с этим ничего не поделаешь. Вот почему такие вещи, как Boost.Asio
также proactor - он будет работать на Windows.
Относительно просто синтезировать реактор поверх реакторной системы. Ваша реакторная петля просто становится диспетчером событий.
В отличие от попыток сделать эффективные реакторы на Windows приходится прибегать к опросу потоков. Это то, что делает Cygwin. Их реализация POSIX select()
запускает поток для каждого файлового дескриптора (которые являются просто абстракциями для Windows HANDLE), каждый из которых занят опросом своего дескриптора, ожидающего, можно ли прочитать данные. Не эффективно.
Теперь действительно очень интересно то, что Microsoft уже разработала среду выполнения Linux для Windows 10. Это реализация уровня системных вызовов (которая в корне отличается от cygwin). Это поддерживает системные вызовы, необходимые для epoll()
, select()
И это действительно работает для труб, розеток и т. д. Что я действительно, действительно хочу знать, так это как они достигли этого? Ответы на открытку, пожалуйста...