0MQ底层队列设计
ypipe_t has a yqueue_t. pipe_t relates two ypipe(s)。pipe_t就是0MQ框架内使用的底层队列。
yqueue_t的设计目的。

yqueue_t 的结构成员

这个队列的设计与std::deque有的相似,都用chunk双向链表实现,同样避免FIFO队列对内存过度频繁的分配和释放。yqueue_t不支持随机访问,以及遍历迭代。yqueue_t采用了一个spare_chunk,保存最近一次访问过后释放或分配出来的chunk,提高空闲chunk的cache亲和性。并且spare_chunk使用了lock-free的atomic_ptr_t。
begin_chunk指向chunk链表的开始端,back_chunk指向chunk链表的有效尾端。
yqueue只支持类似std::deque的pop_front, pop_back, push_back。
pop_front当消耗完一个chunk,然后空闲出一个chunk,替换spare_chunk。
push_back当接近可写chunk的末端,就会分配出一个chunk或取出spare_chunk,链入到链表尾端,end_chunk指向这个新的chunk。
pop_back可能会使当前可写chunk空闲,但这个空闲出来的chunk不会放到spare_chunk。
接着就是ypipe_t, 其设计目的:

ypipe_t 结构成员:

这里的lock-free,同样关键在atomic_ptr_t类型的成员。同样是利用cas(compare_and_swap)替代解决某些情况的锁。这里并没有实现RCU这类lock-free读写并发算法,也不支持读之间的并发。设计目的,明确指出,只有一条线程可以在任何指定时刻读,以及一条线程可以在任何指定时刻写,换句话说,读写可以无锁并发,但读之间不可并发,写之间也不可以并发。
这里的读写lock-free,w指向yqueue的back,r指向yqueue的front,f指向yqueue未flush的位置。也就是f在w前,r是不会指向到f和w之间的位置,也就是yqueue未空也是不可读的。读写之前的竞态关键就是当r到达了f的位置。这时使用了一个atomic_ptr_t类型的c去进行lock-free解决。准确来说,竞态可能会发生在读线程的读和写线程的flush时刻。
如果你要使用这个ypipe作为你的程序的队列的话,你还是得用同步原语控制读之间以及写之间的同步。最理想的使用就是,同时只有一条线程可读,另一条线程可写,读写两条线程之间是可以lock-free并发的。如果用锁的话,当发生竞态就有一条线程要进入内核态等待,另一条线程也要进入内核态去唤醒。详细请看前面关于futex的文章。
最后就是pipe_t。

主要结构成员:



pipe_t关联inpipe的读端,关联outpipe的写端。在这一层并提供一个事件槽。

==================================================================

ypipe_t用于两个小组件, 一个是IO消息的底层upipe_t,上面封装一层pipe_t,用于某些类型的0MQ socket (socket_base_t),另一个是cmd命令的cpipe_t用于mailbox,而mailbox是向io_thread_t以及rearer_t对象通讯的队列。mailbox并不是底层io文件,但借用了signaler_t(实现用某种文件系统文件),并实现i_poll_event接口,让mailbox的"io"纳入到操作系统的poller。当通过mailbox发送命令与mailbox的拥有者通讯时,就会在某个reactor线程中处理事件。参看mailbox::send

==========================================================
整个zmq框架内部,对象之间使用mailbox进行通讯。
来看一下zmq context


cxt_t将reaper_t回收线程,io_thread_t 以及 socket_base_t 的mailbox 按放在 slots 指针数组。
slots[0] = &term_mailbox
slots[1] = reaper->get_mailbox()
slots[2 .. 2+io_nr] = io_thread->get_mailbox()
slots[...] = socket_base->get_mailbox()
这里要清楚,
1. 可以向一个io_thread发送command,并让command在目标io_thread上运行。
2. 向socket_base_t发送command,不会唤醒io_thread,因为socket_base_t不负责io,负责io的stream_engine_t,这才是我们通常理解的stream connection。你zmq_poll这个socket_base_t的控制线程会被唤醒,并执行这个命令。但是一般不会直接向socket_base_t发送command。而是通常继承它的tid(实质是slots的索引)的pipe_t,在写入pipe_t后,向pipe_t发送send_activate_read(send_command),就会最终向它的父对象(不是继承关系,而是创建关系)socket_base_t发送command。
======================================================
在zmq框架内部有这样一张 pipe 网络。
1. 首先0MQ socket 不是我们理解的传统意义的socket(某个连接的插口对),一个0MQ socket可以有多个连接,并且是透明的。
2. 每个0MQ socket会一对 pipe 用于编程者的访问。
3. 0MQ socket里面每个连接(session)都有一对 pipe,0MQ socket会透明地将消息在它的 pipe 和 多个session的pipe之间进行交换。
4. ctx_t包含了slots(mailbox,一种借用了signaler可以被socket poll的pipe),对象间的消息通讯使用这些mailbox。
5. zmq_proxy,透明地将一个socket_base_t的pipe和另一个socket_base_t的pipe的消息进行交换。
0MQ底层队列设计的更多相关文章
- 基于redis的延迟消息队列设计
需求背景 用户下订单成功之后隔20分钟给用户发送上门服务通知短信 订单完成一个小时之后通知用户对上门服务进行评价 业务执行失败之后隔10分钟重试一次 类似的场景比较多 简单的处理方式就是使用定时任务 ...
- 基于redis的延迟消息队列设计(转)
需求背景 用户下订单成功之后隔20分钟给用户发送上门服务通知短信 订单完成一个小时之后通知用户对上门服务进行评价 业务执行失败之后隔10分钟重试一次 类似的场景比较多 简单的处理方式就是使用定时任务 ...
- ActiveMQ学习总结(8)——消息队列设计精要
消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一. 当今市面上有很多主流的消息中间件,如老牌的Activ ...
- Apache Druid 底层存储设计(列存储与全文检索)
导读:首先你将通过这篇文章了解到 Apache Druid 底层的数据存储方式.其次将知道为什么 Apache Druid 兼具数据仓库,全文检索和时间序列的特点.最后将学习到一种优雅的底层数据文件结 ...
- 算法与数据结构题目的 PHP 实现:栈和队列 设计一个有 getMin 功能的栈
刚入手了一本<程序员代码面试指南>,书中题目的代码都是 Java 实现的,琢磨着把这些代码用 PHP 敲一遍,加深印象. 题目:设计一个有 getMin 功能的栈 —— 实现一个特殊的栈, ...
- Python 番外 消息队列设计精要
消息队列已经逐渐成为企业IT系统内部通信的核心手段.它具有低耦合.可靠投递.广播.流量控制.最终一致性等一系列功能,成为异步RPC的主要手段之一.当今市面上有很多主流的消息中间件,如老牌的Active ...
- Asp.Net Core 快速邮件队列设计与实现
发送邮件几乎是软件系统中必不可少的功能,在Asp.Net Core 中我们可以使用MailKit发送邮件,MailKit发送邮件比较简单,网上有许多可以参考的文章,但是应该注意附件名长度,和附件名不能 ...
- C中级 消息队列设计
引言 - 补充好开始 消息队列在游戏服务器层应用非常广泛. 应用于各种耗时的IO操作业务上.消息队列可以简单理解为 [消息队列 = 队列 + 线程安全]本文参照思路如下, 最后献上一个大神们斗法的场 ...
- 【Java TCP/IP Socket】深入剖析socket——TCP通信中由于底层队列填满而造成的死锁问题(含代码)
基础准备 首先需要明白数据传输的底层实现机制,在http://blog.csdn.net/ns_code/article/details/15813809这篇博客中有详细的介绍,在上面的博客中,我们提 ...
随机推荐
- python中生成器与迭代器
可迭代对象:一个实现了iter方法的对象是可迭代的 迭代器:一个实现了iter方法和next方法的对象就是迭代器 生成器都是Iterator对象,但list.dict.str虽然是Iterable(可 ...
- 四jmeter脚本开发
4.1工作区介绍 4.2http协议录制 a.使用badboy进行录制(目前公司测试系统使用badboy界面不友好,暂时不用,之后再补充) b.jmeter代理服务器进行录制 (1)浏览器代理配置(以 ...
- 02--Java Jshell的使用 最适合入门的Java教程
JShell JShell目标 Java Shell 工具(简称:JShell)是一个用于学习Java编程语言和构建Java代码原型的交互式工具.JShell是一个Read-Evaluate-Prin ...
- PSTAT 115 Homework4 课业解析
PSTAT 115 Homework4 课业解析 题意: 蒙特卡洛采样之拒绝采样 解析: 给定一个概率分布p(z)=p~(z)/Zp,p~(z)已知,Zp为归一化常数,为未知数.对该分布进行拒绝采样, ...
- javascript domAPI整理
对一般兼容性和特点做了标识(主要是ie8+) 节点类型 节点类型 节点值 标签节点(Element) 1 属性节点(Attr) 2 文本节点(Text) 3 CDATA节点(CDATASetion) ...
- css过渡transition属性
一.CSS3 过渡 (一).CSS3过渡简介 CSS3过渡是元素从一种样式逐渐改变为另一种的效果. 实现过渡效果的两个要件: 规定把效果添加到哪个 CSS 属性上 规定效果的时长 定义动画的规则 过渡 ...
- .NET Core 3.1 编写混合 C++ 程序
前言 随着 .NET Core 3.1 的第二个预览版本发布,微软正式将 C++/CLI 移植到 .NET Core 上,从此可以使用 C++ 编写 .NET Core 的程序了. 由于目前仅有 MS ...
- Java 8 - 行为参数化
前言: 以下内容来源于java8实战一书,我将里面学习的内容做一个整理,方便没空读书的小伙伴快速入门实战java8 正文: 假设一个果农收获了一园的苹果,他需要你根据他的条件筛选出满意的苹果 首先我们 ...
- [开源] gnet: 一个轻量级且高性能的 Golang 网络库
Github 主页 https://github.com/panjf2000/gnet 欢迎大家围观~~,目前还在持续更新,感兴趣的话可以 star 一下暗中观察哦. 简介 gnet 是一个基于 Ev ...
- hadoop2.6集群环境搭建
版权声明:本文为博主原创文章,未经博主允许不得转载. 一.环境说明 1.机器:一台物理机 和一台虚拟机 2.Linux版本:[Spark@S1PA11 ~]$ cat /etc/issueRed Ha ...