[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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第2篇 机器学习基础 —(3)机器学习库之Scikit-Learn

前言:Hello大家好,我是小哥谈。Scikit-Learn(简称Sklearn)是Python 的第三方模块,它是机器学习领域当中知名的Python 模块之一,它对常用的机器学习算法进行了封装,包括回归(Regressi…

【windows Docker镜像占用许多空间:将数据迁移到D盘】

查看其占据的空间 导出数据到D盘 首先退出docker C:\Users\lxh>wsl --shutdownC:\Users\lxh> C:\Users\lxh>wsl --export docker-desktop-data docker-desktop-data.tar 正在导出,这可能需要几分钟时间。 操作成功完成。C:\Users\lxh> C:\Users\lxh&g…

软件无线电处理平台解决方案:330-基于FMC接口的Kintex-7 XC7K325T PCIeX4 3U PXIe接口卡

基于FMC接口的Kintex-7 XC7K325T PCIeX4 3U PXIe接口卡 一、板卡概述 本板卡基于Xilinx公司的FPGAXC7K325T-2FFG900 芯片,pin_to_pin兼容FPGAXC7K410T-2FFG900 ,支持PCIeX8、64bit DDR3容量2GByte,HPC的FMC连接器,北京太速科…

安达发|汽车零配件在生产上常常会遇到哪些困难?

汽车零配件在生产上常常会遇到许多困难,这些困难涉及到技术、质量、成本和供应链等多个方面。以下是一些常见的困难及其解决方案: 1.技术难题:汽车零配件的生产需要高度的技术支持,尤其是在新材料、新工艺和新设备的应用上。解决技…

【蓝桥每日一题]-二分类型(保姆级教程 篇3) #路标设置 #跳石头

今天接着讲二分题型 目录 题目:路标设置 思路: 题目:跳石头 思路: 题目:路标设置 思路: 求:放n个路标后的最小空旷指数 二分查找:对空旷指数进行二分 二分依据: 该空旷指数下放…

XR Interaction ToolKit

一、简介 XR Interaction Toolkit是unity官方的XR交互工具包。 官方XRI示例地址:https://github.com/Unity-Technologies/XR-Interaction-Toolkit-Examples 2023.3.14官方博客,XRIT v2.3 https://blog.unity.com/engine-platform/whats-new-in-xr-int…

Windows Server 2008安装

1.典型 2.稍后安装操作系统 3.Microsoft Windows 4.尽量虚拟机名称也改一下,我忘记改了 5. 默认40G差不多了,不用修改了 6.直接点完成 7.配置处理器和镜像 8.中文简体 9.现在安装 10.第一个就行(完全安装) 11.我接受&#xff0c…

基于stm32F4的智能宠物喂食器的设计:LVGL界面、定时喂食喂水通风

宠物喂食器 一、功能设计二、元器件选型三、UI设计四、原理图设计五、源代码设计六、成品展示 实物链接:https://m.tb.cn/h.5iCUX6H?tkPL65WXCEipQ CZ3457 一、功能设计 1、设计一个触摸屏作为人机交互 2、通过触摸屏设置时间定时喂食喂水通风 3、获取当前水槽的…

PlantSimulation安装帮助文档端口被占用的解决办法

PlantSimulation安装帮助文档端口被占用的解决办法 从PlantSimulaiton(TPS)2201开始帮助文档开始使用在线,如果使用本地则需要安装本地文档服务器。但是在安装过程中你可能会遇到,5000断开被占用的情况。解决办法如下&#xff1a…

axios 实现请求 loading 效果

前景提要: ts 简易封装 axios,统一 API 实现在 config 中配置开关拦截器 loading 分为全屏 loading 和局部 loading。 axios 中设置 loading 只能设置全屏 loading,因为局部 loading 需要当前局部的 dom,在 axios 中显然拿不到发…

取消Excel打开密码的两种方法

Excel设置了打开密码,想要取消打开密码是由两种方法的,今天分享这两种方法给大家。 想要取消密码是需要直到正确密码的,因为只有打开文件才能进行取消密码的操作 方法一: 是大家常见的取消方法,打开excel文件之后&a…

c++装饰器模式

前言 装饰器模式,就是可以对一个对象无限装饰一些东西,而且可以没有顺序。比如一个人可能只会说出他的名字,但是可以让他再说哈哈,可以说完哈哈之后再说哇哇。如何后面又不想装饰了,不需要改类原来的代码,…

IS200EPSMG1AED 使用Lua创建逻辑脚本或完整程序

IS200EPSMG1AED 使用Lua创建逻辑脚本或完整程序 IS200EPSMG1AED 是一种支持网络的I/O控制器,它执行类似于可编程逻辑控制器(PLC)的控制、逻辑和监控功能。然而,与PLC不同,X-600M是为基于网络的应用而设计的。X-600M可以使用内置网络服务器和…

【256MB+256MB】起,含税低至88元!飞凌嵌入式FET113i-S全国产核心板上市

超低价、超灵活、超全能!飞凌嵌入式FET113i-S全国产核心板正式发布!整板采用100%国产工业级元器件,含税价最低仅需88元! FET113i-S核心板基于全志T113-i工业级处理器开发设计,主频1.2GHz,配备多核多架构&a…

如何开始开发一个跑腿App系统?

1. 确定需求和功能规划 开始开发之前,需明确系统所需的基本功能,包括用户注册、登录、下单、配送员匹配、订单跟踪等。这些功能需要在系统设计之初明确。 2. 技术选型 选择适合的技术栈。前端可以使用框架如React、Vue.js,后端可选择Node…

智慧财务的未来

信息化时代,财务管理不再局限于传统的手工操作,而是借助RPA技术实现了自动化、智能化的转型。智慧财务作为财务管理的一种新模式,将为企业提供更加高效、便捷的服务,使企业能够更好地适应市场需求的变化,在瞬息万变的市…

史上最详细注释,用flask写一个博客系统

文本用flask写个博客系统,源码带有详细注释,通俗易懂,拿去就能用。博客效果如下,博客首页: 这个博客麻雀虽小,但五脏俱全。有如下功能: 博客文章浏览用户注册用户登录/登出发文章/修改文章/删除…

vue:js中合并对象的方法

目前比较常用的一共有三种 1、使用object.assign() 它可以将一个或多个对象的属性复制到目标对象中&#xff0c;第一个参数就是目标对象&#xff0c;这里举个例子&#xff1a; <template><div>{{data}}</div> </template> <script> export de…

陪诊接单系统|陪诊系统助力您获取更好的服务

为了解决陪诊过程中的种种瓶颈和问题&#xff0c;我们开发了一款创新的陪诊接单系统&#xff0c;旨在为客户提供更加高效、专业的陪诊服务。该系统凭借其独特的功能和特点&#xff0c;助力您获取更好的陪诊服务体验。 陪诊系统功能&#xff1a; 1、诊前约号&#xff1a;人工带…

MySql优化经验分享

一条sql的具体执行过程 连接 我们怎么查看MySQL当前有多少个连接&#xff1f; 可以用show status命令&#xff0c;模糊匹配Thread&#xff0c; Show global status like "Thread%" show global variables like wait timeout;—非交互式超时时间&#xff0c;如JDBC…