环形队列 Ring Buffer

上一篇降到了环形队列的一些性质。现在来说实现。

从需求开看环形队列需要进行两个操作

  • 写入
  • 读取

而作为一个大小有限内存区域,就会有临界状态来限制置否能写入成功,或者是成功的取

  • 写入-> 如果队列满了就不能写入或者写入失败
  • 读取-> 如果队列空时就读取失败或者不能读取

因此总共就至少有4个操作。这里以元素都是int为例,定义一个 RingBuffer。

class RingBuffer
{
public:RingBuffer();bool insert(int elem);bool fetch(int& elem);bool isEmpty();bool isFull();private:static const int m_size = 5;int m_RingBufferBuffer[m_size];int m_wPtr;int m_rPtr;
};

m_wPtr和m_rPtr记录的是数组m_RingBufferArray的索引。分别用来记录当前操作的位置。这里需要小心的是作为标记位置同时有两种方式

  • 表示已经读取或者写入的位置
  • 表示下一次将要读取或者写入的位置

根据判断空或者满的判断条件不同,则表示的内容可以不一样。最终能够不会让判断的条件唯一就行了。我们实现的RingBuffer采用标记位置为已经写入的位置和已经读取过的位置。

因此在没有临界条件时。进行插入的逻辑是先移动写指针,然后在进行插入,同理读取也是现需要移动读指针在进行数据读取。

// 插入
m_wPtr = (m_wPtr + 1) % m_size;
m_RingBufferArray[m_wPtr] = elem;// 读取
m_rPtr = (m_rPtr + 1) % m_size;
elem = m_RingBufferArray[m_rPtr];

如前面提到的,进行操作时需要考虑临界条件。初始状态可以看作为空即读指针和写指针都相等

bool RingBuffer::isEmpty()
{bool ret = false;if (m_rPtr == m_wPtr){ret = true;}return ret;
}

而对于如果判断为队列满,需要稍稍不同。因此读指针代表已读的位置,假如允许写指针去写入读指针所在的位置就没办法区分到底当前状态为空还是满。

因此需要选择一个不会产生歧义的条件来避免和判空区间发生重复,即当需要写入的下一个位置为读指针所在位置时就判定为满,就不能在写入数据了,当然这就会浪费一格位置,虽然也能通过比方说加入标志位来解决问题,但是同时让逻辑变得复杂了一层。而且实际使用中唤醒队列大小不可能只有5个,因此是可以接受的。如下图,2位置并没有被写入,但是也判定为满。

因此最终我们补全了判空和满的代码

bool RingBuffer::isFull()
{bool ret = false;if (((m_wPtr+1) % m_size) == m_rPtr){ret = true;}return ret;
}

到这里,环形队列也就是无锁队列的核心数据结构就实现了。最后在构造函数里对状态进行初始化

RingBuffer::RingBuffer()
{m_wPtr = 0;m_rPtr = 0;memset(m_RingBufferArray, 0, sizeof(m_RingBufferArray));
}

针对有两个线程同时操作的数据结构,如果没有同步控制机制就会有并发问题。这涉及到CAS的使用以及内存一致性保护。在下一篇中将针对这两点的实现讲解。

无锁队列原理及实现(二)相关推荐

  1. 无锁队列原理及实现(一)

    背景 在进行实际生产多线程开发的时候通常不会直接使用使用锁机制来操作线程间传递的数据,特别是对效率要求很高的场景中.最典型的就是音视频项目或者网络项目.这里先拿网络传输场景举例, 从这篇开始就开始详细 ...

  2. Linux无锁共享内存,优秀数据结构学习 - 共享内存无锁队列的实现(二)

    优秀数据结构学习 - 共享内存无锁队列的实现(二) 优秀数据结构学习 - 共享内存无锁队列的实现(二) 1 关键技术 操作系统提供的进程间通信机制有文件.socket.消息队列.管道.共享内存等.其中 ...

  3. 地表最强队列-ZMQ无锁队列

    1 前言 老规矩,介绍前先简单聊一下为啥需要无锁队列,主要解决了哪些问题.首先是为啥需要无锁队列,我们最常见的就是利用锁保护临界资源,在多线程中进行队列操作,当并发量起来会带来大量的线程切换开销,而使 ...

  4. (Erlang语言)运行时中的无锁队列及其在异步线程中的应用

    本文首先介绍 Erlang 运行时中需要使用无锁队列的场合,然后介绍无锁队列的基本原理及会遇到的问题,接下来介绍 Erlang 运行时中如何通过"线程进度"机制解决无锁队列的问题, ...

  5. Erlang运行时中的无锁队列及其在异步线程中的应用

    本文首先介绍 Erlang 运行时中需要使用无锁队列的场合,然后介绍无锁队列的基本原理及会遇到的问题,接下来介绍 Erlang 运行时中如何通过"线程进度"机制解决无锁队列的问题, ...

  6. 原理剖析(第 012 篇)Netty之无锁队列MpscUnboundedArrayQueue原理分析

    原理剖析(第 012 篇)Netty之无锁队列MpscUnboundedArrayQueue原理分析 - 一.大致介绍 1.了解过netty原理的童鞋,其实应该知道工作线程组的每个子线程都维护了一个任 ...

  7. ZMQ无锁队列的原理与实现

    ZMQ无锁队列的原理与实现 前言 1. 为什么需要⽆锁队列 2. 无锁队列的实现(参考zmq,只支持一写一读的场景) 2.1 无锁队列前言 2.2 原⼦操作函数介绍 2.3 yqueue_t的chun ...

  8. 实用的无锁队列(二)

    上次的修改一下 链接在此:[无锁队列一] //c_buffer.h class c_data {private:s_memory v_root = NULL;s_memory *v_r = NULL; ...

  9. 无锁队列的几种实现及其性能对比

    一.无锁队列用在什么样的场景? 当需要处理的数据非常多,比如行情数据,一秒处理非常多的数据的时候,可以考虑用无锁队列.但是如果一秒只需要处理几百或者几千的数据,是没有必要考虑用无锁队列的.用互斥锁就能 ...

最新文章

  1. 2020年的AI现状
  2. Linux基础命令---sysctl修改内核参数
  3. BZOJ 3504: [Cqoi2014]危桥 [最大流]
  4. 获取用户真实Ip地址
  5. STM32CubeMx官网下载HAL库文档资料
  6. 『飞秋』关于ASP.NET MVC+Repository+Service架构的一些思考
  7. Docker+FastDFS+SpringBoot 快速搭建分布式文件服务器
  8. 错误: 找不到或无法加载主类 helloworld_你还不知道Java的类加载机制?
  9. sharepoint 特别信息 --- 自个乐去吧~~
  10. 【目标检测】SPPNet算法详解
  11. DNS和VIP的区别
  12. 在开发板显示24位的bmp格式图片
  13. 嵌入式系统硬件构成-基于ARM的嵌入式开发板介绍
  14. 白菜萝卜的做法 - 凉拌菜
  15. DSL是什么意思?Mbps是什么意思?
  16. mysql外联多表查询
  17. wincc7.0显示无法访问服务器,WinCC 7.0 SP3 安装时提示网络连接不可用,无法安装...
  18. 支配树 Dominator Tree
  19. 电子工程可以报考二建_我是电子信息工程专业,可以报考二级建造师吗?要..._二建考试_帮考网...
  20. android paint跑马灯,Android使用Canvas实现跑马灯

热门文章

  1. 磁轴承快速原型仿真系统ETest_DEV研究
  2. 【无人机】地面站QGC:软件架构
  3. 中超风云2服务器维护,时隔三年“中超”IP强势回归《中超风云2》手游现已开启预约...
  4. 地图瓦片:矢量瓦片和栅格瓦片详解
  5. 贪吃蛇 java下载_Java实现贪吃蛇游戏源码
  6. typora中图片转base64
  7. python可以应用lbm_格子玻尔兹曼方法(LBM)Python 程序提速
  8. VSCode中使用Pylint检查python代码
  9. 为何蔡徐坤每条微博转发量100万+?用大数据扒一扒他的真假流量粉
  10. Spark操作Kudu