[common c/c++] ring buffer/circular buffer 环形队列/环形缓冲区

前言:

ring buffer / circular buffer 又名环形队列 / 环形缓冲区,其通过开辟固定尺寸的内存来实现反复复用同一块内存的目的。由于预先开辟了固定尺寸的内容,所以当数据满的时候,可以有两种处理方式,具体使用哪一种按照实际需求,具体如下:

1)当队列满的时候,新来的数据会覆盖最古老的数据,这种数据结构的特点是数据的写入不会因为队列满了而停止,同时也会导致旧数据的丢失,常用在一些对老旧数据不敏感的场景。如果数据很重要且不希望被丢弃,那么不要使用这种覆盖的模式,比如 流媒体场景下,每一帧数据都要确保完整地被渲染出来,不然会出现跳帧和音画同步无法完成等问题,所以不适合这种模式。

2)当数据满的时候,block 或者禁止写入操作,直到队列有空间时再允许写入。这种模式下可以保证数据不被覆盖掉。

环形队列优势在于,不需要反复开辟(alloc)内存空间,可以反复复用同一块内存区域,这样避免了反复申请释放内存带来的时间开销和内存碎片化。

ps:下文以环形队列来代替 ring buffer / circular buffer / 环形缓冲区。

环形队列的最小可操作单位并不是固定的,可以是一个字节的内存空间,也可以是N个字节,或者是其他数据结构体类型的内存尺寸,这取决于环形队列最小单元的尺寸。比如  char ringbuffer[409600] 的环形队列,可操作的最小单位一般就是一个字节,long long ringbuffer[409600] 的环形队列,很可能就是按照8个字节作为一个最小粒度单元的。

下文中使用单位一次来指代环形队列的最小可操作元素,同样地一个步进单位也是指一次地址移动的步长。

设计思路:

环形队列 的管理需要 4 个 index 值 ,队列开始处 start,队列结束处 end,已填充区域的头部 head,已填充区域的尾部 tail。因为环形队列是固定尺寸的缓冲区,所以一般情况下使用内存地址来表示者 4个 index。

start 和 end 表示开辟的固定内存空间的 起始位置,用来限定整个环形队列可以游走的空间范围。start指向内存开始的地址,end指向内存结束的地址。

head 和 tail 反映已经写入数据的内存空间的 起始位置,这里用反映而不是用表示是说明 head 和 tail 对于地址的表示 和 start 和 end 有所不同。 head 指向下一次可写入地址的开始位置,注意这里是下一次可写入,而不是上一次写入的尾部。tail 指向已经写入区域的最老的内存单元的地址。head 指向的是未被写入的地址,tail指向的是已经被写入的地址。

几个重要的限定条件:

1)head index 只能指向未被写入的位置。

A ‘head’ index - the point at which the producer inserts items into the buffer.

2)tail index 可以指向任何位置。

A ‘tail’ index - the point at which the consumer finds the next item in the buffer.

3)队列满:当 head index 前进一个 单位后等于 tail index 的时候,队列就满了,这个时候其实还剩余一个未被写入的单位,因为 head 永远是指向未被写入的单位。所以队列满等于 head + sizeof(element) = tail 。如果head 和 tail 是指针,那么 head + 1 = tail,因为指针 加 1 会根据指针类型自动调节字节步长。

the buffer is full when the head pointer is one less than the tail pointer.

伪代码:

bool isempty(){

  if(tail == head)

    return true;

  else

    return false;

}

4)队列空:当 tail index 等于 head index 的时候,队列就空了。

Typically when the tail pointer is equal to the head pointer, the buffer is empty

伪代码:

bool isfull(){

  if(tail == head+1)

    return true;

  else

    return false;

}

上面伪代码只做说明,不可实用,因为实际情况下需要考虑到 head 和 tail 到达和越过  end 时需要重置到 start 位置重新计算的问题。

是否需要考虑同步问题:

是,需要考虑同步问题。

单生产者和单消费者场景下,产消双方没有机会操作相同的队列单元,但是head index 和 tail index 还是存在 race condition 的。

多生产者和多消费者场景下,更需要加锁。

implement with c++ 11:

队列满则覆盖版老数据版本:

队列满则等待可用空间版本:

implement with c:

队列满则覆盖版老数据版本:

队列满则等待可用空间版本:

lock free practice:

队列满则覆盖版老数据版本:

队列满则等待可用空间版本:

参考:

Circular Buffers — The Linux Kernel documentationicon-default.png?t=N7T8https://www.kernel.org/doc/html/v4.20/core-api/circular-buffers.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/114358.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

思路视野杂志思路视野杂志社思路视野编辑部2023年第24期目录

公共文化 公共图书馆文旅融合实践与模式思考 白雪1-3 公共图书馆管理与服务创新路径分析 陈静4-6 提升办公室文书档案管理工作的实践探讨 黄强7-9 《思路视野》投稿邮箱:cn7kantougao163.com(注明投稿“《思路视野》”) 崔编辑Q Q :296078736 微信号&am…

ajax-axios发送 get请求 或者 发送post请求带有请求体参数

/* axios v0.21.1 | (c) 2020 by Matt Zabriskie */ !function(e,t){"object"typeof exports&&"object"typeof module?module.exportst():"function"typeof define&&define.amd?define([],t):"object"typeof export…

瑞明达:聚“追梦”之力,共圆“经济梦”

矢志不渝,笃行不怠,争当“一心一意同国行”的无悔“追梦人”。过往几年,国际形势风高浪急,国内环境复杂多变,在后疫情时代、经济恢复压力等多种超预期的因素冲击下,瑞明达团队全面贯彻落实国家发展政策&…

为什么 SIEM 是抵御网络威胁的最佳防御手段

随着 IT 服务和基础设施趋向于混合模式,以及最近数据的激增,组织必须拥有一个集中式安全解决方案来跟踪用户的行为和关键安全事件。 威胁行为者越来越善于检测和利用组织网络中的漏洞,网络攻击也在不断发展。虽然管理员可以对已经发生的攻击…

USART HMI串口屏+单片机通讯上手体验

USART HMI串口屏单片机通讯上手体验 🔖本文采用淘晶驰4.3寸IPS串口屏实物验证,HMI串口屏经简单配置即可快速实现,串口通讯效果。串口屏上手简单,有独立的开发套件,容易上手,驱动显示和功能代码独立。本文仅…

ipv6简单实验案例

R1配置: ipv6 interface GigabitEthernet0/0/0 ipv6 enable ipv6 address auto global ipv6 route-static 2001:21:: 64 2001:12::1 R2配置: ipv6 dhcp enable dhcpv6 pool test address prefix 2001:21::/64 excluded-address 2001:21::1 interface Gi…

EasyExcel复杂表头数据导入

目录 表头示例导入代码数据导出 表头示例 导入代码 Overridepublic void importExcel(InputStream inputStream) {ItemExcelListener itemExcelListener new ItemExcelListener();EasyExcel.read(inputStream, ImportItem.class, itemExcelListener).headRowNumber(2).sheet()…

深入了解汽车级功率MOSFET NVMFS2D3P04M8LT1G P沟道数据表

汽车级功率MOSFET是一种专门用于汽车电子领域的功率MOSFET。它具有高电压、高电流、高温、高可靠性等特点,能够满足汽车电子领域对功率器件的严格要求。汽车级功率MOSFET广泛应用于汽车电机驱动、泵电机控制、车身控制等方面,能够提高汽车电子系统的效率…

Java进阶(List)——面试时List常见问题解读 结合源码分析

前言 List、Set、HashMap作为Java中常用的集合,需要深入认识其原理和特性。 本篇博客介绍常见的关于Java中List集合的面试问题,结合源码分析题目背后的知识点。 关于的Set的博客文章如下: Java进阶(Set)——面试时…

9.Vue前端使用iframe集成帆软报表的单点登录

一、背景 需要把帆软报表内嵌到若依里面来。 二、帆软设置 2.1 帆软报表的url 打开帆软后端里面的【目录管理】查看具体报表的url 帆软报表的具体地址为: Frm聚合报表地址: 【帆软的服务http】+【/webroot/decision/view/form?viewlet=demo/demo.frm】 CPT普通报表的地…

【腾讯云 HAI域探秘】使用Stable Diffusion大模型生成惊世骇俗的图片!

文章目录 前言环境准备高性能应用服务 HAI资格申请购买HAI高性能服务 生成图片界面汉化:输入提示词生成图片参数列表:根据提示词生成图片 总结:优点:缺点: 前言 AI绘画工具的发展历史可以追溯到2014年,当时…

SQL INNER JOIN 关键字(内部连接)

SQL INNER JOIN 关键字(内部连接) 内部链接INNER JOIN关键字选择两个表中具有匹配值的记录。 SQL INNER JOIN 语法 SELECT column_name(s) FROM table1 INNER JOIN table2 ON table1.column_name table2.column_name; 注释:INNER JOIN 与 …

4.多层感知机-3GPT版

#pic_center R 1 R_1 R1​ R 2 R^2 R2 目录 知识框架No.1 多层感知机一、感知机1、感知机2、训练感知机3、图形解释4、收敛定理5、XOR问题6、总结 二、多层感知机1、XOR2、单隐藏层3、单隐藏层-单分类4、为什么需要非线性激活函数5、Sigmoid函数6、Tanh函数7、ReLU函数8、多类分…

MFC 窗体插入图片

1.制作BMP图像1.bmp 放到res文件夹下,资源视图界面导入res文件夹下的1.bmp 2.添加控件 控件类型修改为Bitmap 图像,选择IDB_BITMAP1 3.效果

【嵌入式开发学习】__软件工程师的关键原则-18个系统设计概念

目录 前言 01. 域名系统 (DNS) 02. 负载均衡器 03. API 网关 04. 内容交付网络 (CDN) 05. 正向代理与反向代理 06. 缓存 07. 数据分区 08. 数据库复制 09. 分布式消息系统 10. 微服务 11. 数据库 12. 前端缓存 13. 后端缓存 14. 安全性 15. 高可用性与容错性 …

都是80m²小户型,凭啥她家那么好看!福州中宅装饰,福州装修

杨桥新苑 本案来自杨桥新苑的住宅, 质朴弥漫在80㎡的小家, 自然淡雅的木纹,精炼的玄关隔断, 简约的设计里传达着中式的静谧风雅, 简练的空间加入中国元素, 让人从进门开始就沾染一丝艺术气息。 风格&a…

Apache Pulsar 在腾讯云上的最佳实践

导语 由 StreamNative 主办的 Pulsar Meetup Beijing 2023 在2023年10月14日完美落幕,本次活动大咖云集,来自腾讯、滴滴、华为、智联招聘、RisingWave 和 StreamNative 的行业专家们一起,深入探讨 Pulsar 在生产环境中的最佳应用实践&#x…

Docker学习——②

文章目录 1、Docker是什么1.1 Docker本质1.2 Docker的引擎迭代1.3 Docker和虚拟机的区别1.4 Docker 为什么比虚拟机资源利用率高,启动快?1.5 Docker 和 JVM 虚拟化的区别? 2、Docker架构3、Docker生态3.1 新时代软件诉求3.2 Docker 解决方案 …

OSPF高级特性1(重发布,虚链路)

目录 OSPF高级特性(1) 一、OSPF不规则区域类型 二、解决方案 1、使用虚连接 演示一:非骨干区域无法和骨干区域保持连通 演示二:骨干区域被分割 2、使用多进程双向重发布 OSPF高级特性(1) 一、OSPF不规则区域类型 产生原因:区…