物联网操作系统AliOS Things探索与实践
上QQ阅读APP看书,第一时间看更新

2.8 环形缓冲池(ring buffer)

2.8.1 概念

环形缓冲池(ring buffer),也称圆形缓冲区(circular buffer)、圆形队列(circular queue)、循环缓冲区(cyclic buffer),是一种固定尺寸、头尾相连的缓冲池的数据结构,适合缓存数据流。环形缓冲池多用于两个任务之间传递数据,是标准的先入先出(FIFO)模型。

一般来说,若多任务之间共享数据需要使用互斥机制(mutex)来进行同步,以保证共享数据不会发生不可预测的修改与读取,然而互斥机制的使用也会带来额外的系统开销。环形缓冲池的引入就是为了有效解决这个问题,以提高系统资源利用率。

2.8.2 环形缓冲池的初始化与重置

1.ring buffer初始化

函数原型:kstat_t krhino_ringbuf_init(k_ringbuf_t *p_ringbuf, void *buf, size_t len, size_t type, size_t block_size)

ring buffer初始化需配置ringbuf的长度、类型、存储元素长度及在内存中实际的存储位置。其中,管理结构体k_ringbuf_t的主要数据成员包括:

(1)buf:ring buffer在内存中的实际开始位置。

(2)end:ring buffer在内存中的实际结束位置。

(3)head:存储在缓冲池中的有效数据的开始位置,即读指针。

(4)tail:存储在缓冲池中的有效数据的结尾位置,即写指针。

(5)freesize:标示缓冲池当前剩余可用空间大小。

(6)type:标示缓冲池的类型,“固定长度(RINGBUF_TYPE_FIX)”或是“可变长度(RINGBUF_TYPE_DYN)”。

(7)block_size:标示存储在缓冲池中的单个数据块长度,只针对RINGBUF_TYPE_FIX有效。

2.ring buffer重置

函数原型:kstat_t krhino_ring.buf_reset(k_ringbuf_t *p_ringbuf)

ring buffer重置会清除缓冲池中的数据块,并重置ring buffer的读/写指针、剩余可用空间大小。

2.8.3 环形缓冲池的写入与读取

1.ring buffer的写入

函数原型:kstat_t krhino_ringbuf_push(k_ringbuf_t *p_ringbuf,void *data, size_t len)

ring buffer写入的步骤主要包括:

(1)判断缓冲池是否已满,若已满,则返回RHINO_RINGBUF_FULL错误。

(2)判断缓冲池的剩余空间能否写入数据块,若不能,则返回RHINO_RINGBUF_FULL错误。

(3)重新校准缓冲池的写指针及剩余空间大小。

(4)压入数据块。

ring buffer写入流程如图2-11所示。

图2-11 ring buffer写入流程

2.ring buffer的读取

函数原型:kstat_t krhino_ringbuf_pop(k_ringbuf_t *p_ringbuf, void *pdata, size_t *plen)

ring buffer读取的步骤主要包括:

(1)判断缓冲池是否为空,若为空,则返回RHINO_RINGBUF_EMPTY错误;

(2)读取数据块;

(3)校准缓冲池读指针及剩余空间大小。

ring buffer读取流程如图2-12所示。

图2-12 ring buffer读取流程

2.8.4 环形缓冲池的容量判断

1.判断ring buffer是否为空

函数原型:uint8_t krhino_ringbuf_is_empty(k_ringbuf_t *p_ringbuf)

若环形缓冲池的剩余空间大小与预设的环形缓存池长度一致,会判定此时缓存池为空。

2.判断ring buffer是否已满

函数原型:uint8_t krhino_ringbuf_is_full(k_ringbuf_t *p_ringbuf)

环形缓存池是否已满的判断会区分RINGBUF_TYPE_FIX类型和RINGBUF_TYPE_DYN类型。对于RINGBUF_TYPE_FIX类型,若环形缓存池的剩余空间小于预设的固定数据块长度,则判定缓存池已满。对于RINGBUF_TYPE_DYN类型,若环形缓存区的剩余空间小于8字节,则判定缓存池已满。