当前位置: 首页 > news >正文

环形缓冲区 ring buffer 概述

环形缓冲区 ring buffer 概述

1. 简介

环形缓冲区(ring buffer),是一种用于表示一个固定尺寸、头尾相连的缓冲区的数据结构,适合缓存数据流。也称作环形缓冲区(circular buffer),环形队列(circular queue),循环缓冲区(cyclic buffer)。

2. 特点及应用场景

环形缓冲区的特点:

  • 固定大小
  • 线性地址空间
  • 先进先出FIFO
  • 高效读取(数据消费后不需要移动其他数据)

环形缓冲区的应用场景:

  • 网络通信(TCP/IP网络协议栈数据缓存)
  • 任务间的通信(生产者消费者缓存、异步通信优化)
  • 操作系统内核(串口网口等驱动设备数据缓存、log日志缓存)
  • 音频/视频流处理(流媒体传输、实时编解码)

环形缓冲区的典型实现:

  • Linux内核kfifo:采用镜像指示位法实现无锁环形队列,缓冲区大小为2的幂
  • RT-Thread的ringbuffer:为嵌入式系统优化,支持零拷贝操作和中断安全API
  • Boost库circular_buffer:支持动态扩容和元素保留策略,提供STL兼容接口

3. 设计要点

3.1 如何在线性地址空间上实现循环读写?

所谓循环读写是指在环形缓冲区的末尾读写之后,下一次读写需要回到环形缓冲区首地址的过程。也称作指针回绕。

对于环形缓冲区首地址m_buffer和缓冲区大小bufferSize是已知条件,通过增加读指针m_readIndex和写指针m_writeIndex就可以解决循环读写问题。

char* buffer; // 环形缓冲区指针
uint32_t bufferSize; // 环形缓冲区大小
uint32_t readIndex; // 读指针,指向下一个要读取的位置
uint32_t writeIndex; // 写指针,指向下一个要写入的位置

计算公式

读索引 = 读指针 % 缓冲区长度; // 基础: 读写指针取模
写索引 = 写指针 % 缓冲区长度;读索引 = 读指针 & (缓冲区长度 - 1); // 优化: 当bufferSize为2的幂时,取模运算可优化为按位与
写索引 = 写指针 & (缓冲区长度 - 1);

假设 环形缓冲区大小bufferSize为4

  • 环形缓冲区的初始状态,大小为4

m_readIndex = 0
m_writeIndex = 0

 start              end  │                 │   ▼                 ▼   
┌─────┬─────┬─────┬─────┐
│     │     │     │     │
└─────┴─────┴─────┴─────┘▲  ▲                   │  │                   r  w                     
  • 环形缓冲区的写入1个数据A

m_readIndex = 0
m_writeIndex = 1 (1 % 4 = 1 或 1 & (4 -1) = 1)

 start              end  │                 │   ▼                 ▼   
┌─────┬─────┬─────┬─────┐
│  A  │     │     │     │
└─────┴─────┴─────┴─────┘▲     ▲               │     │               r     w              
  • 环形缓冲区的写入4个数据ABCD(缓冲区满)

m_readIndex = 0
m_writeIndex = 0 (指针回绕 4%4=0 或 4 & (4 -1) = 0)

 start              end  │                 │   ▼                 ▼   
┌─────┬─────┬─────┬─────┐
│  A  │  B  │  C  │  D  │
└─────┴─────┴─────┴─────┘▲ ▲                    │ │                    r w                             
  • 环形缓冲区的读取2个数据AB

m_readIndex = 2 (2 % 4 = 2 或 2& (4 -1) = 2)
m_writeIndex = 0

 start              end  │                 │   ▼                 ▼   
┌─────┬─────┬─────┬─────┐
│     │     │  C  │  D  │
└─────┴─────┴─────┴─────┘▲           ▲         │           │         w           r         

3.2 如何判断缓冲区空和满?

读写指针在相同位置时,缓冲区可能为空或者满。

可以用以下几种方法判断:

  • 计数法:维护写入个数count,count == 0 为空,count == bufferSize为满。需要通过原子操作保证线程安全
  • 预留空位法: 写入时保留最后一个位置。当(writeIndex + 1) % bufferSize == readIndex时为满,writeIndex == readIndex时为空
  • 镜像指示位法:通过镜像标志位标记读写指针(0至 2n-1)是否进入镜像区间(n 至 2n-1)。当读写指针相等且镜像标志位相同时为空,当读写指针相等且镜像标志位不同时为满。当缓冲区大小为2的幂时,可省略镜像标志位,使用异或运算writeIndex == (readIndex ^ bufferSize )直接判断满状态。RT-Thread、Linux内核(kfifo)采用该方案

3. 3 数据溢出与数据覆盖策略?

环形缓冲区的写入6个数据ABCDEF(缓冲区溢出,数据区满后写入数据模式为覆盖)

m_readIndex = 2 (覆盖了2个数据AB,需要移动2位)
m_writeIndex = 2( 6 % 4 = 2 或 6 & (4 -1) = 2)

 start              end  │                 │   ▼                 ▼   
┌─────┬─────┬─────┬─────┐
│  E  │  F  │  C  │  D  │
└─────┴─────┴─────┴─────┘▲ ▲        │ │        r w                

数据溢出时一般有以下几种策略:

  • 阻塞写入:抛出异常或阻塞等待缓冲区有足够空间,保证数据完整性(如日志记录)
  • 覆盖写入:覆盖旧数据,适用于实时流处理(如音视频传输)
  • 动态扩容:缓冲区大小扩容,但会破坏环形缓冲区的固定内存特性

Reference:

  1. Circular buffer - Wikipedia
  2. CSerialPort/include/CSerialPort/ibuffer.hpp

相关文章:

环形缓冲区 ring buffer 概述

环形缓冲区 ring buffer 概述 1. 简介 环形缓冲区(ring buffer),是一种用于表示一个固定尺寸、头尾相连的缓冲区的数据结构,适合缓存数据流。也称作环形缓冲区(circular buffer),环形队列&…...

Spring源码之解决循环依赖 三级缓存

目录 三级缓存核心原理 循环依赖的解决过程 1. Bean A创建过程中提前曝光工厂 2. Bean B创建时发现依赖A,从缓存获取 3. Bean A继续完成初始化 三级缓存的作用总结 二级缓存为何不够解决缓存依赖? 三级缓存如何解决? 为什么不直接在…...

山东大学计算机图形学期末复习9——CG12上

CG12上 几何管线末端:顶点已组装成基本图元(Primitives,如点、线、三角形)。 主要任务: 裁剪:视锥体是一个三维空间区域(由近裁剪面、远裁剪面和侧面组成),超出该区域的图…...

关于软件测试开发的一些有趣的知识

文章目录 一、什么是测试?二、为什么要软件测试软件测试三、测试的岗位有哪些四 、软件测试和开发的区别五、走测试岗位为什么还要学开发。4、优秀的测试人员具备的素质我为什么走测试岗位 一、什么是测试? 其实这个问题说简单也不简单,说难…...

在Solana上使用 Scaled UI Amount 扩展

本指南提供 Solana Web3.js (Legacy v 1.x) 和 Solana Kit (v 2.x) 版本。选择适当的选项卡以查看你首选库的代码片段和说明: Solana Web3.js (Legacy)Solana Kit 概述 Solana Token-2022 程序 引入了强大的扩展,增强了代币功能,使其超越了…...

线性表之数组与栈详解

线性表之数组与栈详解 前言一、数组(Array)1.1 数组的基本概念1.2 数组的实现与操作1.3 数组的应用场景1.4 数组的优缺点 二、栈(Stack)2.1 栈的基本概念2.2 栈的实现方式2.3 栈的应用场景 2.4 栈的优缺点 三、数组与栈的对比总结…...

车载以太网驱动智能化:域控架构设计与开发实践

title: 车载以太网驱动专用车智能化:域控架构设计与开发实践 date: 2023-12-01 categories: 新能源汽车 tags: [车载以太网, 电子电气架构, 域控架构, 专用车智能化, SOME/IP, AUTOSAR] 引言:专用车智能化转型的挑战与机遇 专用车作为城市建设与工业运输…...

【Redis】redis用作缓存和分布式锁

文章目录 1. 缓存1.1 Redis作为缓存1.2 缓存更新、淘汰策略1.3 缓存预热、缓存穿透、缓存雪崩和缓存击穿1.3.1 缓存预热(preheating)1.3.2 缓存穿透(penetration)1.3.3 缓存雪崩(avalanche)1.3.4 缓存击穿&…...

深度学习中独热编码(One-Hot Encoding)

文章目录 独热编码独热编码的作用独热编码的优点独热编码的缺点场景选择独热编码(PyTorch实现)替代方案 实际使用分析:对对象类型使用独热编码为什么使用独热编码是合适的?📌 场景说明:📌 为什么…...

如何根据竞价数据判断竞价强度,是否抢筹等

竞价强度判断方法 价格变化幅度 观察开盘价与前一交易日收盘价的差距 :如果一只股票在开盘集合竞价阶段价格大幅高于前一交易日收盘价,说明市场对该股票的预期较为积极,可能有资金在主动抬高价格,这是一种较强的竞价强度表现。例如…...

Codex与LangChain结合的智能代理架构:重塑软件开发的未来

🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 引言:当代码生成遇见智能决策 想象以下场景: 凌晨三点:你需要紧急修复一个遗留系统的内存泄漏漏洞,但代码注释缺失且逻辑复杂; 产品经理需求变更:要求在24小时内将现有…...

2025年PMP 学习十八 第11章 项目风险管理 (11.5~11.7)

2025年PMP 学习十八 第11章 项目风险管理 (11.5~11.7) 第11章 项目风险管理 序号过程过程组1规划风险管理规划2识别风险规划3实施定性风险分析规划4实施定量风险分析规划5规划风险应对执行6实施风险应对执行7监控风险监控 文章目录 2025年PMP 学习十八…...

2025年PMP 学习十七 第11章 项目风险管理 (11.1~11.4)

2025年PMP 学习十七 第11章 项目风险管理 (11.1~11.4) 第11章 项目风险管理 序号过程过程组1规划风险管理规划2识别风险规划3实施定性风险分析规划4实施定量风险分析规划5规划风险应对执行6实施风险应对执行7监控风险监控 文章目录 2025年PMP 学习十七…...

impala

Impala,它是 Cloudera 开发的开源 实时 SQL 查询引擎,专为 Hadoop 设计。与 Presto 类似,Impala 用于交互式分析,但架构和设计理念有所不同。以下是 Impala 的核心特点和工作原理: 一、Impala 核心架构 1. 组件组成 …...

湖北理元理律师事务所:债务优化中的双维支持实践解析

在债务压力与生活质量失衡的社会议题下,法律服务机构的功能边界正在从单一的法律咨询向复合型支持延伸。湖北理元理律师事务所通过“法律心理”双维服务模式,探索债务优化与生活保障的平衡路径,其方法论或为行业提供实践参考。 法律框架&…...

Redis设计与实现——Redis命令参考与高级特性

Redis命令参考 数据类型相关命令 SET:设置键值,支持过期时间、不存在/存在条件。GET:获取键值,若键不存在返回 nil。INCR/DECR:将键的整数值增1/减1,键不存在时初始化为0。MSET/MGET:批量设置…...

TCP/UDP协议原理和区别 笔记

从简单到难吧 区别就是TCP一般用于安全稳定的需求,UDP一般用于不那么需要完全数据的需求,比如说直播,视频等。 再然后就是TPC性能慢于UDP。 再然后我们看TCP的原理(三次握手,数据传输,四次挥手&#xff0…...

JavaScript基础-对象的相关概念

在JavaScript中,对象是核心的数据结构之一,几乎所有的高级功能都围绕着对象展开。理解对象的基本概念、创建方法以及操作方式对于掌握JavaScript至关重要。本文将详细介绍JavaScript中对象的相关概念,包括对象的定义、属性的操作、原型链和面…...

如何通过交流沟通实现闭环思考模式不断实现自身强效赋能-250517

感谢一直以来和我交流沟通的朋友们。 闭环思考 文字部分(25-05-04)这一天是青年节,在这一天与青年朋友交流这个是事先规划好的: “可以猜一猜,博士会被撤销吗?导师会被处理吗?千万不要回复&…...

震荡指标工具

一、引言 - 可视化数字烛台工具是对传统蜡烛图的补充,旨在帮助交易者更有效地进入和退出交易,提高交易利润。 - 通过分析蜡烛图,结合烛台震荡指标,提出了一个辅助视觉工具来辅助交易决策。 二、烛台指标与交易策略 -图表通过平均开…...

【自然语言处理与大模型】大模型(LLM)基础知识④

(1)微调主要用来干什么? 微调目前最主要用在定制模型的自我认知和改变模型对话风格。模型能力的适配与强化只是辅助。 定制模型的自我认知:通过微调可以调整模型对自我身份、角色功能的重新认知,使其回答更加符合自定义…...

返回码的方案对比和思考

前言 一般我们定义 Restful 接口返回码,常见的就是 const 定义 code , StatusToText() 来实现定义 msg, 在封装1 ~ 2个返回方法(success、error)就可以实现,只是突然想到这样设计是违反开闭原则的&#xf…...

Flink 的任务槽和槽共享

在 Apache Flink 中,任务槽(Task Slot) 和 槽共享组(Slot Sharing Group) 是资源管理和任务调度的关键机制。它们决定了 Flink 如何在集群中分配资源并执行任务。 一、任务槽(Task Slot) 1. 定…...

实验七 基于Python的数字图像水印算法

一、实验目的 掌握图像水印的应用; 掌握我国版权保护的发展现状; 掌握常见的数字图像水印算法。 二、实验内容 学习内容补充: 数字水印的鲁棒性评价主要采用含水印图像提取出的水印与原始水印的相似程度,使用归一化相关(NC,Nor…...

C语言:在 Win 10 上,gcc 如何编译 gtk 应用程序

在 Windows 10 上使用 g(或 gcc)编译基于 GTK 的 C 语言程序是完全可行的,且相比 Tcc 更为推荐,因为 g(GNU 编译器套件)对 GTK 的支持更加完善,配置也更简单。以下是详细步骤和注意事项&#xf…...

Vue.js---watch 的实现原理

4.7 watch 的实现原理 watch本质上就是使用了effect以及options.scheduler 定义watch函数: // watch函数:传入参数source以及回调函数function watch(source , cb) {effect(() > source.foo,{scheduler(){// 回调函数cb()}})}watch接收两个参数分别是source和c…...

Linux_ELF文件

目录 前言: 一、ELF文件的类型 二、ELF文件的组成格式 1. ELF头部(ELF Header) 2. 节头表(Section Header Table) 3. 程序头表(Program Header Table) 4. 节(Sections)与段(Segments) 三、ELF文件从形成到加载轮廓 1、ELF可执行文件形成过程 2、 可执行文…...

磁盘I/O子系统

一、数据写入磁盘流程 当执行向磁盘写入数据操作的时候,会发生如下的一系列基本操作。假设文件数据存在于磁盘扇区上,并且已经被读入到页缓存中。 进程使用write()系统调用写入文件。内核更新映射到文件的page cache。内核线程pdflush负责把页缓存刷入…...

【2025 技术指南】如何创建和配置国际版 Apple ID

想要体验更丰富的应用生态、使用国际版专属服务,或访问更多开发者工具?一个国际版 Apple ID 能帮你实现这些需求。本教程将详细介绍如何注册国际版 Apple ID 并正确配置支付信息,全程操作简单,适合开发者和技术爱好者参考。 一、准…...

C++(20): 文件输入输出库 —— <fstream>

目录 一、 的核心功能 二、核心类及功能 三、核心操作示例 1. 文本文件写入(ofstream) 2. 文本文件读取(ifstream) 3. 二进制文件操作(fstream) 四、文件打开模式 五、文件指针操作 六、错误处理技巧…...

05、基础入门-SpringBoot-HelloWorld

05、基础入门-SpringBoot-HelloWorld ## 一、Spring Boot 简介 **Spring Boot** 是一个用于简化 **Spring** 应用初始搭建和开发的框架,旨在让开发者快速启动项目并减少配置文件。 ### 主要特点 - **简化配置**:采用“约定优于配置”的原则,减…...

深入理解指针(6)

目录 1 sizeof和strlen的对⽐ 1.1 sizeof ​编辑1.2strlen 1.3 sizeof 和 strlen的对⽐ 2 数组和指针笔试题解析 2.1 ⼀维数组 ​编辑 2.2 字符数组 3 指针运算笔试题解析 3.1 题⽬1: ​编辑3.2 题目2 3.3 题目3 3.4 题目4 3.5 题目5 3.6 题目6 3.7…...

力扣HOT100之二叉树:108. 将有序数组转换为二叉搜索树

这道题之前做过,思路又给忘了,这道题用递归做是最简单的。 由于得到的数组是有序的,我们只需要取出中间位置的元素medium作为根节点,然后medium左边的剩余元素组成根节点的左子树,medium右边的剩余元素组成根节点的右子…...

手撕I2C和SPI协议实现

手撕I2C和SPI协议实现 目录 I2C协议原理I2C位操作实现I2C驱动代码编写SPI协议原理SPI位操作实现SPI驱动代码编写 I2C协议原理 I2C(Inter-Integrated Circuit)是一种串行通信总线,使用两根线:SCL(时钟线&#xff09…...

452. Minimum Number of Arrows to Burst Balloons

题目描述 这道题用leetcode官方的解答反而搞复杂了。本题其实就是求重叠区间的交集。先按照区间左端点从小到大排序。然后拿出第一个区间作为【当前区间交集】的初始值。遍历后面的区间看那个区间和【当前交集】是否有重叠。如果有重叠则将【当前交集】和【当前区间】求交集并更…...

React 中,闭包陷阱

文章目录 前言1. 经典闭包陷阱示例过期状态问题 2. 解决方案2.1 正确声明依赖数组2.2 使用 useRef 捕获最新值**2.3 使用函数式更新(针对状态更新)****2.4 使用 useCallback 冻结闭包** **3. 异步操作中的闭包陷阱****事件监听示例** **4. 自定义 Hooks …...

代码复现5——VLMaps

项目地址 1 Setup # 拉取VLMaps仓库,成功运行后会在主目录生成文件夹vlmapsgit clone https://github.com/vlmaps/vlmaps.git#通过 conda 创建虚拟环境conda create -n vlmaps python=3.8 -yconda activate vlmaps #激活环境cd vlmaps # 切换到项目文件下bash install.ba…...

qt6 c++操作qtableview和yaml

保存qtableview数据到yaml文件从yaml文件读取数据到qtableview qtableview在UI界面拖放。 代码是问chat百度的深度探索。 - name: a1address: db1.dbw10type: int - name: a2address: db1.dbx1.0type: bool写到yaml,写前检查 bool plot1::isRowValid(const QStan…...

使用UniApi调用百度地图API的需要注意的地方

目录 前言 一、百度开放平台 1、功能简介 2、地点搜索服务 3、按行政区划检索API 二、Uniapi集成百度API 1、API集成流程 2、访问接口的定义 3、业务调用集成 三、可能遇到的问题 1、指定输出格式无效 2、返回数据的总数 四、总结 前言 在之前的系列博客中&#xf…...

(9)python开发经验

文章目录 1 os.path.join()拼接路径2 条件变量3 添加临时环境变量 更多精彩内容👉内容导航 👈👉Qt开发 👈👉python开发 👈 1 os.path.join()拼接路径 os.path.join() 是 Python 中处理文件路径拼接的核心函…...

windows 10 做服务器 其他电脑无法访问,怎么回事?

一般我们会先打开win10自己的防火墙策略,但是容易忽略 电脑之间 路由器上的防火墙,此时也需要查看一下,可以尝试先关闭路由器防火墙,如果可以了,再 设置路由器上的防火墙规则。 将路由器的上网设置 改成 路由模式 &a…...

mysql中limit深度分页详细剖析【爽文】

目录 一 mysql中limit深度分页 1.1 背景描述 1.2 mysql深度分页很慢原因 1.2.1 mysql的sql执行流程 1.2.2 mysql的深度分页很慢原因 1.3 解决办法 1.3.1 覆盖索引 1.3.2 子查询 1.3.3 标签查询 1.3.4 分区表 一 mysql中limit深度分页 1.1 背景描述 Limit深度分页造…...

【C++ Qt】布局管理器

每日激励:“不设限和自我肯定的心态:I can do all things。 — Stephen Curry” 🤔绪论​: 在Qt开发中,界面布局的合理设计是提升用户体验的关键。早期,开发者常采用绝对定位的方式摆放控件,即通…...

Windows系统永久暂停更新操作步骤

目录 Windows系统永久暂停更新操作步骤 打开运行窗口进入注册表编辑器 导航路径图示 新建并配置DWORD值 新建值操作图示数值设置图示 在系统设置中应用暂停 暂停选项图示 注意事项 打开运行窗口 按下键盘上的 Win键 R 组合键,调出“运行”对话框。 进入组策略编…...

Java IO流进阶实战详解(含文件读写、拷贝、加密、字符集)

本文基于 Java 原生 IO 流,从最基础的字节流到字符流,再到实战案例(如文件夹拷贝、文件加密等)进行逐步深入讲解。适合有一定 Java 基础、希望掌握文件读写操作的。 一、前言 Java IO(输入输出)是我们日常…...

JavaScript【7】BOM模型

1.概述: BOM(Browser Object Model,浏览器对象模型)是 JavaScript 中的一个重要概念,它提供了一系列对象来访问和操作浏览器的功能和信息。与 DOM(Document Object Model)主要关注文档结构不同&…...

STM32F10xx 参考手册

6. 什么是寄存器 本章参考资料:《STM32F10xx 参考手册》、《STM32F10xx数据手册》、 学习本章时,配合《STM32F10xx 参考手册》“存储器和总线架构”及“通用I/O(GPIO)”章节一起阅读,效果会更佳,特别是涉及到寄存器说明的部分。…...

使用instance着色

本节我们学习使用instance着色器进行着色 //拾取var handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);handler.setInputAction(function(movement){console.log(movement);var pickedObject viewer.scene.pick(movement.position);if(Cesium.defined(picke…...

MySQL——4、表的约束

表的约束 1、空属性2、默认值3、列描述4、zerofill5、主键6、自增长7、唯一键8、外键9、综合案例 真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性…...

Datawhale PyPOTS时间序列5月第3次笔记

下游任务的两阶段(two-stage) 处理 下载数据并预处理的程序: # ------------------------------- # 导入必要的库 # ------------------------------- import numpy as np import torch from benchpots.datasets import preprocess_physionet2012 from pypots.imp…...