multithreading - ZeroMQ:如何在 ZeroMQ 节点中处理与消息无关的异步事件?
问题描述
假设我有一个带有 ZeroMQ 接口的节点(进程、线程等),比如说一个REP
套接字。这意味着我有一个无限的主循环,它在zmq_recv
orzmq_poll
函数中休眠。
现在该节点还应该从另一个异步事件接收数据。例如,想象一下键盘按钮按下事件或切换 GPIO 引脚或计时器到期。执行还必须在等待这些事件时休眠。
应该如何编写主循环,使其在任一类型的事件(即消息的接收和异步事件的发生)上唤醒?
我可以想到两个解决方案:
首先,一个轮询循环,其中两个事件都以非阻塞方式检查,我每隔几毫秒运行一次循环。就处理负载而言,这似乎并不理想。
其次,我将两个事件的阻塞代码移动到单独的线程中。相反,在主循环中,我睡在一个信号量(或条件变量)上,它是由任一事件的发生发布的。这就是我在传统应用程序中采用的方式,但 Pieter Hintjens 编写的ZeroMQ 指南非常明确地指出不使用信号量:
远离经典的并发机制,如互斥锁、临界区、信号量等。这些是 ZeroMQ 应用程序中的反模式。
那么该怎么办?这里的最佳做法是什么?
解决方案
根据您的操作系统,系统中的大多数事件都是通过一些准备好读取的文件描述符生成的。这通常是它在 Linux、Unix 等上的工作方式。例如,键盘输入通过 STDIN 输入。当然,任何描述的文件描述符都可以包含在 ZMQ 轮询中。
如果事件不是通过可用于 ZMQ 轮询的文件描述符引发的(例如,Windows 上的串行端口准备好读取),我通常使用线程将事件转换为通过 ZMQ 套接字发送的消息。工作得很好。变得不可移植,但这是不可避免的。
GPIO 可能更难。如果它没有得到将 ISR 集成到操作系统驱动程序堆栈中的某些驱动程序的支持,那么您将不得不轮询它。
推荐阅读
- angularjs - $scope 与 $ctrl 有什么区别,什么时候应该使用?
- javascript - 单击类时附加元素
- java - 如果没有构造函数,我怎样才能让这段代码发挥同样的作用?
- terraform - 如何为无服务器应用程序构建 terraform 模板
- vim - 使用 vnoremap 映射函数
- python - scikit-learn 中的 SpectralClustering 与 Spectral_clustering
- google-apps-script - 如何清除所有行范围行
- vb.net - 在应用程序运行中动态更改数据库的位置
- c++ - 有没有办法防止 vtable 在 c++ 中发出?
- c++ - 如何在 OpenGL 3.3 中修复黑屏输出