Ring Buffer(也叫Circular Buffer)原理简单,运行高效,被广泛应用于异步通信和嵌入式系统的内存管理中。
基本元素:
一个固定大小的数组,一个写指针和一个读指针。
读写操作流程:
1)写入三个数据:A,B,C,写指针移到3,读指针位置不变。
2)读取一个数据A,读指针移到1,写指针保持不变。
3)继续写入六个数据:D,E,F,G,H,I,这时候会发生写指针追上读指针的情况(full),处理方法分两种:
a. 优先保证实时性(音视频流),则覆盖旧数据,让新数据进来,这时候读指针需要跟着写指针移动,保证读指针总是指向最旧的数据:
b. 优先保证稳定性(数据存储),舍弃新数据,保持旧数据的完整性,这时候H,I被舍弃(也可能是写操作被反压住):
4)如果发生读取速度加快,比如连续读取7个数据(D,E,F,G,H,I,D),显然,读到第7个数据时读指针追上了写指针,发生了重复读取,这是不允许的,所以第七个数据D不会被读出,读操作被强制暂停。
Ring Buffer如何区分满还是空?
第一种方法是读写分别计数。但是计数器不可能无限大,总会存在0~n循环计数,所以不能完全排除满和空互相混淆的情况。
第二种方法是保持一个存储单元为空。如果读写指针指向同一个位置,则buffer为空;如果写指针比读指针落后一个位置,则buffer为满。这种方法的优点是简单可靠,但是会浪费存储空间。
第三种方法是镜像指示位。如果buffer长度为n,则将逻辑地址空间拓展为0~2n-1,其中0~n-1是物理地址空间,n~2n-1是镜像逻辑地址空间(虚拟空间)。如果n是2的幂,指针的最高bit就可以指示目前是否进入了虚拟空间;如果不是,则需要单独一个bit的指示位来记录指针是否进入虚拟空间。这个方法区分满or空的条件很简单,如果读写指针相差n,判为满;如果读写指针相等,判为空。
Ring Buffer的特点:
固定大小的MEM,避免了动态内存管理的复杂性;缺点是可能会丢数据。