简体   繁体   English

如何使用ZeroMQ唤醒线程

[英]How to wake up threads with ZeroMQ

My current program is receiving messages via zmq. 我当前的程序正在通过zmq接收消息。 A thread is waking up from time to time and checks what zmq received last. 线程不时唤醒,并检查上次收到的zmq。

Now I want to improve this setup and actually process every message that comes in, instead of just the last one when waking up. 现在,我想改进此设置,并实际处理收到的每条消息,而不仅仅是唤醒时的最后一条消息。 Also I want my thread just to wake up, when there is something new. 另外,当有新内容出现时,我也想唤醒我的线程。 Is there a way how zmq can force my thread to wake up, as soon as he has a new message for my thread. 一旦zmq对我的线程有新消息,是否有办法让zmq强制我的线程唤醒。

ZMQ is all about Actor Model programming. ZMQ全部涉及Actor模型编程。 It is a Reactor. 它是一个反应堆。 You use zmq_poll() to wait for one of a set of sockets to become ready for reading. 您可以使用zmq_poll()等待一组套接字中的一个准备就绪以进行读取。 When one does, you read from it. 当您这样做时,您会从中阅读。

So your program becomes a loop, at the top you call zmq_poll() which blocks (or times out), and after that you deal with whichever socket has become ready to read, and then loop. 因此,您的程序成为一个循环,在顶部调用zmq_poll()进行阻塞(或超时),然后再处理已准备好读取的任何套接字,然后循环。

In contrast, call backs belong in Proactor Model programming. 相反,回叫属于Proactor模型编程。 You say what should happen up front (by setting up the call back), and then that will happen no matter what. 您说应该先发生(通过设置回叫),然后不管发生什么。

The important thing to remember is, Reactor and Proactor really, really don't mix. 要记住的重要一点是,Reactor和Proactor确实不会混合使用。 Never try to blend the two together if you can help it, it will be the source of endless confusion. 如果可以帮助,请不要将两者融合在一起,这将是无休止的混乱之源。 Either go all in with one or the other. 要么全力以赴。 This is why ZeroMQ doesn't have a call back mechanism. 这就是ZeroMQ没有回调机制的原因。

The poor mixing of the two styles is the reason why the IPC transport for ZeroMQ doesn't work on Windows. 两种样式的不良混合是ZeroMQ的IPC传输在Windows上不起作用的原因。 ZeroMQ's reactor is zmq_poll() . ZeroMQ的反应堆是zmq_poll() Fundamentally this relies on the OS providing a reactor. 从根本上讲,这取决于提供反应器的OS。 On Linux this is select() or epoll() which as is standard for a *nix can work with any file descriptor (network sockets, IPC pipes, serial ports, etc). 在Linux上,这是select()epoll() ,这对于* nix是标准的,可以与任何文件描述符一起使用(网络套接字,IPC管道,串行端口等)。

In contrast Windows does not provide a universal reactor. 相反,Windows不提供通用反应器。 The closest it gets is select() , which works only on network sockets. 它获得的最接近的是select() ,它仅在网络套接字上有效。 To block on a pipe in Windows your using calls that take call backs. 要在Windows中阻塞管道,请使用带有回叫功能的呼叫。 Windows is, fundamentally, a proactor system and there's not a lot to be done about it. 从根本上说,Windows是一个proactor系统,关于它,有很多事情要做。 This is why things like Boost.Asio is also proactor - it'll work on Windows. 这就是为什么Boost.Asio东西也是proactor的原因-它可以在Windows上运行。

It is relatively straight forward to synthesise a proactor on top of a reactor system. 在反应器系统顶部合成前驱体是相对简单的。 Your reactor loop simply becomes an event dispatcher. 您的反应堆循环仅成为事件调度程序。

In contrast attempts at doing efficient reactors on Windows have to resort to polling threads. 相反,在Windows上进行高效反应器的尝试必须诉诸于轮询线程。 This is what cygwin does. cygwin就是这样做的。 Their implementation of POSIX select() runs a thread per file descriptor (which are just abstractions for Windows HANDLEs), each one busy polling their handle waiting to see if data can be read. 他们在POSIX select()实现中为每个文件描述符运行一个线程(这只是Windows HANDLE的抽象),每个忙于轮询其句柄以等待是否可以读取数据。 Not efficient. 没有效率。

Now the really, really interesting thing is that Microsoft have now gone and done a Linux runtime for Windows 10. This is a system call level implementation (so radically different to cygwin). 现在,真正非常有趣的事情是,Microsoft已经离开并完成了Windows 10的Linux运行时。这是系统调用级别的实现(与cygwin完全不同)。 That does support the system calls required for epoll() , select() , and it does work for pipes, sockets, etc. What I really, really want to know is how have they achieved this? 这确实支持epoll()select()所需的系统调用,并且确实适用于管道,套接字等。我真正想要知道的是它们如何实现的? Answers on a postcard please... 请在明信片上回答...

As you have mentioned " Also I want my thread just to wake up, when there is something new. ", this can be achieved if a callback is assigned to data receive , so whenever a new data arrives the callback would be executed. 正如您提到的“ 还有一些新的东西我也希望我的线程醒来。 ”, 如果将回调分配给data receive则可以实现这一点 ,因此每当新数据到达时,都会执行该回调。

But after reading about the zeromq and referring the following links: 但是在阅读了有关zeromq并引用以下链接之后:

Is it possible to add an event handling to ZeroMQ to act when data is received/sent? 是否可以向ZeroMQ添加事件处理以在接收/发送数据时采取行动?

Does ZeroMQ have a notification/callback event/message for when data arrives? 在数据到达时,ZeroMQ是否具有通知/回调事件/消息?

It looks like as of now, ZeroMQ does not implement any callbacks that would notify us when a new data is received . 到目前为止,ZeroMQ尚未实现任何回调,这些回调将在收到新数据时通知我们 You can definitely check for the new data by using zmq_recv in blocking mode (but this would not mean waking up when a new data comes, it would just keep blocking until the data comes). 您绝对可以通过在阻塞模式下使用zmq_recv来检查新数据(但这并不意味着在收到新数据时就醒来,它只会一直阻塞直到数据到来为止)。

One possible solution as stated in the above links: 如以上链接所述,一种可能的解决方案:

You can use SIGNALS along with the zmq which will notify whenever a new data is arrived. 您可以将SIGNALS和zmq一起使用,这将在到达新数据时通知。 The advantage of using signal handler/interrupt handler is that they would not block your code until a new data arrives ( like zmq_recv() in a blocking mode ), instead signal handlers would wake up and only be executed whenever a particular signal is received. 使用信号处理程序/中断处理程序的优点是,它们不会在新数据到达之前就阻塞代码(例如zmq_recv()处于阻塞模式),而信号处理程序将唤醒,并且仅在接收到特定信号时才执行。

Signals like SIGUSR1 / SIGUSR2 can be used as an indication of new data arrival. SIGUSR1 / SIGUSR2这样的信号可以用作新数据到达的指示。 Assign the signal handler to SIGUSR1 to execute the code when a new data is arrived. 当新数据到达时,将信号处理程序分配给SIGUSR1以执行代码。

To wake up a process whenever you have a new data, you would then have to send the data as well as send a signal like: 要在有新数据时唤醒进程,则必须发送数据并发送如下信号:

zmq_send(...);

kill(pid, SIGUSR1);         /*  Send signal SIGUSR1 to the process
                                            whose PID is specified
                                                                   */

The receiving process receives the signal SIGUSR1 and wakes up to execute its handler. 接收进程接收信号SIGUSR1并唤醒以执行其处理程序。 In the handler for this signal, you can read the data and perform some task. 在此信号的处理程序中,您可以读取数据并执行某些任务。 Now, this handler would only be executed again if you send some new data along with SIGUSR1 signal. 现在,仅当您与SIGUSR1信号一起发送一些新数据时,该处理程序才会再次执行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM