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

环形缓冲区 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
http://www.xdnf.cn/news/6864.html

相关文章:

  • Java的线程通信机制是怎样的呢?
  • 数据类型转换
  • Node.js 实战四:数据库集成最佳实践
  • 回溯法理论基础 LeetCode 77. 组合 LeetCode 216.组合总和III LeetCode 17.电话号码的字母组合
  • 数据库故障排查指南:解决常见问题,保障数据安全与稳定
  • 科技晚报 AI 速递:今日科技热点一览 丨 2025 年 5 月 17 日
  • 面向 C 语言项目的系统化重构实战指南
  • 鸿蒙北向源码开发: 检查应用接口dts文件api规范性
  • 望闻问切AI辅助系统(中医门诊病历智能生成工具)
  • 游戏引擎学习第289天:将视觉表现与实体类型解耦
  • 【Java ee初阶】HTTP(4)
  • MakeFile
  • 面向对象详解和JVM底层内存分析
  • 实验七 基于Python的数字图像水印算法
  • Captiks无线惯性动捕及步态分析系统:高频采样+400g超宽动态量程,赋能医疗康复、竞技体育、工业检测三大领域,运动轨迹零盲区追踪!”
  • linux-软件的安装与部署、web应用部署到阿里云
  • 使用glsl 来做视频矫正
  • wifiactivity 界面 要在哪里注册,注销广播?onResume() vs onPause() 的本质区别
  • 电动调节V型球阀:行业应用与材质选择全解析
  • CSS高级技巧
  • 【MySQL】架构和存储引擎
  • 3D个人简历网站 5.天空、鸟、飞机
  • OpenCV 光流估计:从原理到实战
  • mysql中limit深度分页详细剖析【爽文】
  • 黑马点评-用户登录
  • 边缘计算:物联网的“加速器”与“守护者”
  • CentOS 上配置 Docker 使用 NVIDIA GPU
  • 【论文阅读】人脸修复(face restoration ) 不同先验代表算法整理2
  • Python标准库完全指南:os、sys与math模块详解与实战应用
  • DeepSeek指令微调与强化学习对齐:从SFT到RLHF