0MQ 事件驱动 以及 poller
底层IO事件,以及借用socket poller的上层0MQ socket事件。
先来看用于底层和上层的两种poller。
这是用于底层io事件的poller_t,每个socket_base_t都关联到一个poller_t,这个poller_t运行在io_thread_t线程上。
这是运行在0MQ socket层的事件poller。运行在你的控制线程,也就是你编程的线程。
每次你使用zmq_poller_poll都会创建一个sokcet_poller_t去进行poll。
我们要去轮询一个0MQ socket层事件,我们会通过zmq_poll将socket_base_t添加到poller而不是底层fd。
item_t的第二个成员是pollfd,在这里设置为0,表示并不使用fd进行poll。
下面再看socket_poller_t::wait
注释写得很清楚,并不是在poll底层的fd,在poll返回后,遍历所有socket_base_t,并getsocket去取ZMQ_EVENTS事件。zmq_poll被唤醒一般是0MQ socket通过signaler_t去发送唤醒信号。
再来看socket_poller_t::rebuild(), 这是每次socket_poller_t::wait()之初都调用的。
其中它为我们需要进行zmq_poll的socket_base_t进行了pollfd的关联,但不是socket_base_t底层的socket fd,而是ZMQ_FD选项。我们就来看ZMQ_FD到底返回什么给我们。
ZMQ_FD返回的是这个socket_base_t所关联的mailbox的signaler_t的fd。有关mailbox请看上一篇<<底层队列设计>>。到这里就清楚了,zmq_poll会在每个socket_base_t关联的mailbox的signaler_t的fd等待有poll事件发生,而socket_base_t向它所关联的mailbox发送事件就会唤醒zmq_poll。zmq_poll借用了socket poll或select来实现对上层事件的分离等待。每个socket_base_t在初始化的时候都会创建自己的mailbox。
mailbox_t和mailbox_safe_t的不同,就是为zmq_poll服务的。mailbox_t 使用自身的signaler_t,而mailbox_safe_t 使用的signaler_t 是那个使用它的socket_poller_t,并且一个mailbox_safe_t 可以绑定多个signaler_t 。当一个socket_base_t被多个socket_poller_t进行zmq_poll时,每个线程只能运行一个zmq_poll,也就是有多个线程在zmq_poll。这时各个poller只对它自身的signaler_t进行poll,所以是线程安全的。而mailbox_t的情况却是一个signaler_t被多个poller同时在poll。系统调用poll和select是不支持多线程的。