环形缓冲区的扩展方法

时间:2022-08-20 06:22:03

环形缓冲区的扩展方法

摘 要 环形缓冲区是一种高效的数据缓存结构,在多线程异步协作或者分级操作的生产者消费者模式中被广泛使用。它的容量通常是固定不变的,在缓冲区满的时候会有数据丢失或者数据覆盖的问题。本文提出了对环形缓冲区进行扩展的两种方法,并实验论证了两种扩展方法的有效性。

【关键词】环形缓冲区 阶梯式扩展法 链式扩展法

1 环形缓冲区简介

环形缓冲区(ring buffer, circular buffer, cyclic buffer)是一种数据结构,它的大小通常是固定不变的,存储空间在逻辑上首尾相连,如图1所示。环形缓冲区中存储的数据遵循先进先出(FIFO)的规则,通常也称之为环形队列。

1.1 环形缓冲区的实现原理

环形缓冲区的大小(S)通常是固定不变的,有一个读指针(R)和一个写指针(W),R指向环形缓冲区中当前可读数据的位置,W指向环形缓冲区中当前的可写位置。初始状态R和W指向同一位置,环形缓冲区中存储的数据个数(N)初始为0,如图2所示,此时环形缓冲区为空。

每写入一个数据,则N+1,同时移动W指向下一个可写位置。图3是写入3个数据D1, D2和D3之后的环形缓冲区状态。

每读出一个数据,则N-1,同时移动R指向下一个可读数据的位置。图4是读出2个数据D1和 D2之后的环形缓冲区状态。

当写入数据个数N等于S时,环形缓冲区满,此时读写指针R和W指向同一位置,如图5所示。

1.2 环形缓冲区的特点

环形缓冲区的一个重要特点就是读写数据的时候不用进行内存的分配和释放操作(频繁的内存分配和释放操作容易造成内存碎片,从而降低系统性能),只需要在读/写数据之后,相应的移动R/W指针即可。

在多线程异步协作或者分级操作的过程中,环形缓冲区的高性能可以提高整个系统的并发性和吞吐量。

2 环形缓冲区存在的问题

环形缓冲区存在的问题就是它的容量是固定不变的,即最多能够存储的数据量(通常在初始化阶段设定)是固定不变的。在环形缓冲区满的情况下,新数据或者被丢弃,或者覆盖旧数据,或者写线程挂起,等待环形缓冲区进入可写状态。

例如, C++ Boost库的环形缓冲区实现(boost::circular_buffer)在环形缓冲区满的情况下,新数据就会覆盖旧数据,从而造成数据的丢失。

要解决这个问题,就需要对环形缓冲区进行扩展,使它的容量可变,在系统内存允许的范围内扩大存储量。

3 环形缓冲区的扩展方法

通常有两种方法对环形缓冲区进行扩展,第一种方法可以称之为阶梯式扩展法,第二种方法可以称之为链式扩展法。

3.1 阶梯式扩展法

阶梯式扩展法的实现原理:在环形缓冲区满的时候,向系统申请分配一块更大的内存,

并将原有缓冲区内的数据复制到新的内存区,释放原有缓冲区资源,使用新的更大的内存区作为环形缓冲区,以满足数据量增长的需求。

阶梯式扩展法的特点是可以使环形缓冲区的容量随着数据量的增长而呈阶梯式增大。但是在扩展的过程中存在着数据复制的开销,会在一定程度上影响系统的性能。

一个典型的例子,就是基于数组的队列实现(ArrayQueue)。

以图5为例,此时环形缓冲区已满,新数据D11的写入主要分为以下步骤:

1.申请分配一块更大的内存,假设增量大小为5,则内存大小S = 7+5 = 12。

2.从读指针R开始,将原有数据复制到新的内存区,并调整读指针R和写指针W到新的位置。释放原有缓冲区资源。

3.写入新数据D11,移动写指针W至下一位置,N+1。

3.2 链式扩展法

链式扩展法的实现原理:保留使用原有的缓冲区,在环形缓冲区满的时候,向系统申请分配另外一块内存并将它和原有的缓冲区链接起来,共同作为新的环形缓冲区。

链式扩展法相对阶梯式扩展法的优势是避免了数据复制的开销,但是链式扩展法读写指针的移动相对复杂一点,下一个可读或者可写的位置与缓冲区的扩展点(即新申请的内存和原有缓冲区的链接点)密切相关。

还是以图5为例,此时环形缓冲区已满,新数据D11的写入主要分为以下步骤:

(1)申请分配一块增量内存,假设增量大小为5,则总内存大小S = 7+5 = 12。

(2)将原有缓冲区的扩展点和新申请的内存区链接起来,并调整写指针W到新的可写位置。

(3)写入新数据D11,移动写指针W至下一位置,N+1。

3.3 注意事项

经过编码测试,实验结果证明了阶梯式扩展法和链式扩展法都是行之有效的。 需要注意的几个事项,如下所列:

(1)环形缓冲区的可扩展最大容量不可操过系统的允许范围。

(2)极端情况下,如持续的进行写操作导致环形缓冲区达到可扩展最大容量时,不再进行缓冲区扩展。此时系统能力达到极限,数据丢失或数据覆盖不可避免。

(3)持续的缓冲区扩展使得进程占用的系统内存越来越大,导致系统可用内存越来越少。必须增加环形缓冲区的容量缩减机制,使得阶梯式扩展法能够上台阶也能下台阶,使得链式扩展法能够增加扩展点也能减少扩展点。

参考文献

[1]Ring buffer basics,Ken Wada,August 2013,.

[2]ArrayQueue:An Array-Based Queue, .

[3]Implementing Lock-Free Queues,John D.Valois,October 1994,Seventh International Conference on Parallel and Distributed Computing Systems.

作者单位

安飒软件(上海)有限公司 上海市 200127

上一篇:新时期SQLServer数据库应用维护技术探讨 下一篇:一种对讲机射频前端模块的实现