循环缓冲区

这次需要记录之前了解到的参考自linux内核循环队列kfifo的循环缓冲区实现方法。

1、循环缓冲区的实现依靠队列来实现,也就是分配一个数组来存储实际数据。

2、对于一个循环缓冲区来说,我们需要关注的点有:

①缓冲区大小应该设置多少?

②缓冲区队头(in)、队尾(out)初始值?

③缓冲区什么时候为空,什么时候为满?

④如何表示缓冲区长度?

⑤如何入队,如何出队?

⑥如何处理索引值溢出问题?

3、要实现循环缓冲区,我们当然可以用我们数据结构课学过的循环队列来实现,也就是:

设队列大小为M;in和out为下标值。

①循环缓冲区的大小设置为M(没有限制)

②初始化队头 in=0 ,队尾 out = 0

③out == in的时候缓冲区为空,(in+1)%M == out 的时候为满

④缓冲区长度len =(in - out + M)% M

⑤入队:a[in] = data ;  in = (in+1) % M;

    出队:data = a[out] ;  out = (out+1)%M;

⑥索引溢出通过对缓冲区长度进行求余来实现。

4、我们也可以通过另一种更好的方法来实现

同样设队列大小为M;in和out为下标值,但是他们的数据类型都是unsigned int(无符号整型)!!!

①循环缓冲区的大小M设置为2的幂(举例M=2^4=16)

②初始化队头 in=0 ,队尾 out = 0

③out == in的时候缓冲区为空,(in - out ) == M的时候缓冲区为满。

④缓冲区的长度len = (in - out)

⑤入队:a[ in & (M-1) ] = data ; in = ++in;

    出对:data = a[ out & (M-1) ] ; out = ++out;

⑥因为我们缓冲区的大小M设置为2的幂,而unsigned int 型的溢出值肯定是M的2的幂次倍,也就是我们的unsigned int 能表示的数值范围就是2的幂数倍个M。所以,当我们需要得到当前in或者out对应于实际分配到内存的那块循环缓冲区的哪个位置时,可以让in或者out跟(M-1)相与;而更新in和out时,只需要++in和++out。

下面举例说明:

M = 10000;(M设置为16)

(M-1) = 01111; 

由于in和out都是unsigned int数据类型,所以in和out能表示的数值范围为maxof(unsigned_int)=2^32-1 = 4294967295

a、当out在[0,M-1]范围内,就设out = 6(0110),out & (M-1) = 0110,也就是6。嗯,这个简单。

b、当out 在[M,4294967295]范围内,设out = 28(11100),out & (M-1) = 11100 & 01111 = 01100,也就是out等于28时对应的循环缓冲区的位置下标为12。

c、分析一下最极端的情况当out等于unsigned int的最大值4294967295,

    out&(M-1)= 01111,也就是循环缓冲区的最后一个位置。

    而out+1就溢出了,由于unsigned int溢出时变为0,又从最后一个位置加到第一个位置了。

   

总结:

关键字:unsigned int 、按位与运算、2的次幂

a、必须要将M设置为2的次幂。

b、用这种方法不必让in和out对M取余,通过与运算,可以提升速度。

b、unsigned int 溢出时自动变为0,更新in和out时只需要加1即可,方便。

猜你喜欢

转载自blog.csdn.net/weixin_40728015/article/details/81213423
今日推荐