环形缓冲区 ring buffer 概述

news2025/5/18 9:58:45

环形缓冲区 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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

飞帆控件 post or get it when it has get

我在这里分享两个链接: post_get_it 设计 - 飞帆 有人看出来这个控件是干什么用吗? 控件的配置:

SQL里where条件的顺序影响索引使用吗?

大家好,我是锋哥。今天分享关于【SQL里where条件的顺序影响索引使用吗?】面试题。希望对大家有帮助; SQL里where条件的顺序影响索引使用吗? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 SQL 查询中,W…

SAP学习笔记 - 开发豆知识02 - com.sap.cds.services.cds.CdsService 废止,那么用什么代替呢?

我看很多人代码里面用的都是这个CdsService类,可以自从2.0版本往上这个类就没了啊。 它的代替是什么呢?用的CqnService 那么怎么查的呢? 我也是下载好几个包,解压看,然后发现这里还可以直接看,挺方便的。…

OpenResty 深度解析:构建高性能 Web 服务的终极方案

引言 openresty是什么?在我个人对它的理解来看相当于嵌入了lua的nginx; 我们在nginx中嵌入lua是为了不需要再重新编译,我们只需要重新修改lua脚本,随后重启即可; 一.lua指令序列 我们分别从初始化阶段,重写/访问阶段,内容阶段,日志…

什么是路由器环回接口?

路由器环回接口(LoopbackInterface)是网络设备中的一种逻辑虚拟接口,不依赖物理硬件,但在网络配置和管理中具有重要作用。以下是其核心要点: 一、基本特性 1.虚拟性与稳定性 环回接口是纯软件实现的逻辑接口&#x…

【MySQL进阶】如何在ubuntu下安装MySQL数据库

前言 🌟🌟本期讲解关于如何在ubuntu环境下安装mysql的详细介绍~~~ 🌈感兴趣的小伙伴看一看小编主页:GGBondlctrl-CSDN博客 🔥 你的点赞就是小编不断更新的最大动力 &#x1f3…

【数据结构】_二叉树

1.二叉树链式结构的实现 1.1 前置说明 在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树&#x…

给图表组件上点“颜色” —— 我与 CodeBuddy 的合作记录

我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 前段时间,我在开发一个 Vue3 项目的时候,碰到了一个小小的挑战:我想做一个可…

使用 YOLO 结合 PiscTrace 实现股票走势图像识别

在智能投研和金融分析中,自动识别图表中的模式(如 K 线走势、支撑/阻力位、形态结构)成为一种新兴手段。传统的技术分析依赖大量人工判断,而计算机视觉技术的发展,特别是 YOLO 模型在图像识别领域的高效表现&#xff0…

OpenCV中的光流估计方法详解

文章目录 一、引言二、核心算法原理1. 光流法基本概念2. 算法实现步骤 三、代码实现详解1. 初始化设置2. 特征点检测3. 光流计算与轨迹绘制 四、实际应用效果五、优化方向六、结语 一、引言 在计算机视觉领域,运动目标跟踪是一个重要的研究方向,广泛应用…

NBA足球赛事直播源码体育直播M33模板赛事源码

源码名称:体育直播赛事扁平自适应M33直播模板源码 开发环境:帝国cms7.5 空间支持:phpmysql 带软件采集,可以挂着自动采集发布,无需人工操作! 演示地址:NBA足球赛事直播源码体育直播M33模板赛事…

电子电器架构 --- 整车造车阶段四个重要节点

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 钝感力的“钝”,不是木讷、迟钝,而是直面困境的韧劲和耐力,是面对外界噪音的通透淡然。 生活中有两种人,一种人格外在意别人的眼光;另一种人无论…

黑马点评-用户登录

文章目录 用户登录发送短信验证码注册/登录校验登录 用户登录 发送短信验证码 public Result sendCode(String phone, HttpSession session) {// 1.校验手机号if (RegexUtils.isPhoneInvalid(phone)) {// 2.如果不符合,返回错误信息return Result.fail("手机…

十二、Hive 函数

作者:IvanCodes 日期:2025年5月1日 专栏:Hive教程 在数据处理的广阔天地中,我们常常需要对数据进行转换、计算、清洗或提取特定信息。Hive 提供了强大的内置运算符和丰富的内置函数库,它们就像魔法师手中的魔法棒&…

No More Adam: 新型优化器SGD_SaI

一.核心思想和创新点 2024年12月提出的SGD-SaI算法(Stochastic Gradient Descent with Scaling at Initialization)本质上是一种在训练初始阶段对不同参数块(parameter block)基于**梯度信噪比(g-SNR, Gradient Signa…

JSP链接MySQL8.0(Eclipse+Tomcat9.0+MySQL8.0)

所用环境 Eclipse Tomcat9.0 MySQL8.0.21(下载:MySQL Community Server 8.0.21 官方镜像源下载 | Renwole) mysql-connector-java-8.0.21(下载:MySQL :: Begin Your Download) .NET Framework 4.5.2(下…

SEO长尾词与关键词优化实战

内容概要 在SEO优化体系中,长尾关键词与核心关键词的协同作用直接影响流量获取效率与用户转化路径。长尾词通常由3-5个词组构成,搜索量较低但意图明确,能精准触达细分需求用户;核心关键词则具备高搜索量与广泛覆盖能力&#xff0…

机器学习-人与机器生数据的区分模型测试-数据处理1

附件为训练数据,总体的流程可以作为参考。 导入依赖 import pandas as pd import os import numpy as np from sklearn.model_selection import train_test_split,GridSearchCV from sklearn.ensemble import RandomForestClassifier,VotingClassifier from skle…

HelloWorld

HelloWorld 新建一个java文件 文件后缀名为 .javahello.java【注意】系统可能没有显示文件后缀名,我们需要手动打开 编写代码 public class hello {public static void main(String[] args) {System.out.print(Hello,World)} }编译 javac java文件,会生…

SEO 优化实战:ZKmall模板商城的 B2C商城的 URL 重构与结构化数据

在搜索引擎算法日益复杂的今天,B2C商城想要在海量信息中脱颖而出,仅靠优质商品和营销活动远远不够。ZKmall模板商城以实战为导向,通过URL 重构与结构化数据优化两大核心策略,帮助 B2C 商城实现从底层架构到搜索展示的全面升级&…