05|环形缓冲区(Ring Buffer)
1. 什么是环形缓冲区
环形缓冲区(Ring Buffer)用一块固定容量的连续内存循环保存数据。写到数组末尾后,从数组开头继续写;读操作同理。它并非物理上的圆环,而是通过下标回绕实现循环使用。
flowchart LR
A["位置 0"] --> B["位置 1"] --> C["位置 2"] --> D["位置 3"]
D -- "回绕" --> A- 写位置(write):下一次写入的位置。
- 读位置(read):下一次读取的位置。
- FIFO:先写入的数据先被读取。
- 读写后位置向前移动,到末尾则回到起点。
2. 读写位置与空满判断
写入数据时推进写位置;读出数据时推进读位置。不能只看两个位置是否相等来同时判断空和满,必须约定区分方式。
常见方法有两种:
| 方法 | 空的条件 | 满的条件 | 实际可用容量 |
|---|---|---|---|
| 预留一个空槽 | read == write | 写位置再前进一步就碰到读位置 | N - 1 |
| 额外记录有效长度 | 有效长度为 0 | 有效长度为 N | N |
以容量 8、预留一个空槽为例:
flowchart LR
subgraph Buffer["8 个物理槽位"]
direction LR
A["0 已占"] --- B["1 已占"] --- C["2 已占"] --- D["3 已占"] --- E["4 已占"] --- F["5 已占"] --- G["6 已占"] --- H["7 空槽"]
end此时若 read = 0、write = 7,继续写入会让写位置回到 0,与读位置重合,因此判定为满;8 个槽位中最多存 7 个数据。
3. 优缺点与适用场景
优点
- 空间固定、可反复利用,通常无需动态分配。
- 入队和出队只需移动位置,单个元素的基本操作通常是 O(1)。
- 适合持续产生、持续消费的数据流。
局限
- 容量有上限;写入速度长期快于读取速度时,会遇到缓冲区满。
- 满时必须明确策略:拒绝新数据、覆盖旧数据或等待可用空间。
- 多线程或中断并发访问时,需要额外考虑同步与数据可见性。
常见应用:串口收发、音频采样流、日志暂存、生产者—消费者之间的数据传递。
4. 核心结论
环形缓冲区的本质是:固定数组 + 可回绕的读写位置 + 明确的空满规则。选择它时,重点考虑数据流是否连续、容量如何估算,以及缓冲区满时允许怎样处理数据。