环形缓冲区

来源:互联网 发布:好听的网络房间名字 编辑:程序博客网 时间:2024/04/27 22:30

      先来考虑串口接受数据的情况,串口收到一个字节的数据,就会触发串口中断 USART1_IRQHandler 数据字节会存放于串口的硬件寄存器中。但是在RTOS中,通常存在多个线程,如果某个处理串口数据的线程在没有串口数据时阻塞,当下一串口数据到来时,如果该数据线程依然没有唤醒并启动,并读取串口字节,则上一个串口字节丢失了,因此这不是一个优良的设计,我们需要设计一种机制来解决这种潜在的问题。实际上,缓冲机制可以大大缓解这个问题。

所谓缓冲机制,简略的来说,即开辟一个缓冲区,可以是静态数组,也可以是malloc(或mempool)申请的动态缓冲区。在串口中断中,先从串口的硬件寄存器中读取数据,并保存到缓冲区中。这种情况下,我们需要两个变量,一个用于标记当前写入的位置,另外一个用来表示已经被处理的数据的位置。这样当数据处理线程阻塞时,连续收到的数据会保存到缓冲区中而避免了丢失。当中断中已经接收到了一些串口数据后,数据处理线程终于就绪,并开始处理数据,通常来说处理数据的速度必然比接受到的数据要快,因此这样就能解决前面所说的问题。

【图】

聪明的读者发现了,还有一个小问题,缓冲区的长度必然是有限的,终归会有用到头的时候,那该怎么办呢?别担心,缓冲区前面已经被处理过的数据所占用的空间按自然可以重复使用,即,当接收指针指向了缓冲区末尾时,只要缓冲区头的数据已经被处理过了,自然可以直接将缓冲区指针从新设置为头,对于表示已处理的指针变量同理。这样这个缓冲区也就成为了一个环形缓冲区。


环形Buffer的特点

通常包含一个读指针(read_index)和一个写指针(write_index)。读指针指向环形Buffer中第一个可读的数据,写指针指向环形Buffer中第一个可写的缓冲区。通过移动读指针和写指针就可以实现Buffer的数据读取和写入。在通常情况下,环形Buffer的读用户仅仅会影响读指针,而写用户也仅仅会影响写指针。

环形Buffer的原理:

首先在内存里开辟一片区域(大小为 buffer_size),对于写用户,顺次往Buffer里写入东西,一直写到最后那个内存(buffer_size)时再将写指针指向内存区域的首地址,即接下来的数据转个环放到最开始处,只有遇到Buffer里的有效存储空间为0时,才丢掉数据;对于读用户,顺次从Buffer里读出东西,一直写到最后那个内存(buffer_size)时再将读指针指向内存区域的首地址,即接下来转个环从最开始处取数据。

有效存储空间与buffer_size的区别:

有效存储空间是指那些没有存放数据,或者以前存放过但已经处理过的数据,就是可用的空间大小;而buffer_size指的是总大小。

通过上面介绍可知,环形Buffer仍然是一长条区域,只不过其空间会被循环使用而已。示意图如下,根据读写指针的位置可分为两种情况,其中阴影填充部分为数据/已用空间,空白的为可用空间,即有效存储空间。 

  • 其实编程指南里面已经描述了,如果仍不能理解,可以参考以下示意图:

  • 环形Buffer的特点:
  • 通常包含一个读指针(read_index)和一个写指针(write_index)。读指针指向环形Buffer中第一个可读的数据,写指针指向环形Buffer中第一个可写的缓冲区。通过移动读指针和写指针就可以实现Buffer的数据读取和写入。在通常情况下,环形Buffer的读用户仅仅会影响读指针,而写用户也仅仅会影响写指针。
  • 环形Buffer的原理:
  • 首先在内存里开辟一片区域(大小为 buffer_size),对于写用户,顺次往Buffer里写入东西,一直写到最后那个内存(buffer_size)时再将写指针指向内存区域的首地址,即接下来的数据转个环放到最开始处,只有遇到Buffer里的有效存储空间为0时,才丢掉数据;对于读用户,顺次从Buffer里读出东西,一直读到最后那个内存(buffer_size)时再将读指针指向内存区域的首地址,即接下来转个环从最开始处取数据。
  • 有效存储空间与buffer_size的区别:有效存储空间是指那些没有存放数据,或者以前存放过但已经处理过的数据,就是可用的空间大小;而buffer_size指的是总大小。
  • 通过上面介绍可知,环形Buffer仍然是一长条区域,只不过其空间会被循环使用而已。示意图如下,根据读写指针的位置可分为两种情况,其中阴影填充部分为数据/已用空间,空白的为可用空间,即有效存储空间。 

0 0