环形缓冲区的使用

环形缓冲区(Circular Buffer),又被称为环形队列或循环缓冲区,是一种常用的数据结构,特别适用于缓冲流数据的场景,如硬件设备的数据交换、网络通信等

1. 什么是环形缓冲区

环形缓冲区是一个先进先出(FIFO)的闭环的存储空间。相当于就是一个固定大小的数组,和两个指针,读指针和写指针。环形 缓冲区的”环形“特性意味着当任一指针到达数组的末端的时候,会自动回绕到数据开始的位置。

2. 环形缓冲区读写指针

  • 写指针(head): 指向环形缓冲区下一个数据将要写入的位置 , 当有新的数据写入缓冲区的时候,数据会被存储在写指针指向的位置,然后写指针向后移动。如果移动到数组的末尾,并且还有数据要写入的时候,回绕回到数组的开头,继续写入数据。
  • 读指针(tail) :指向下一个将要被读取的数组的位置,和写指针类似,如果读指针度到了数组的末尾,还有数据要读取,它回绕回到数组的开头,继续读取数据。

3. 环形缓冲区读写区域

  • 当写指针(head)在读指针(tail)前面的时候,表示数据是连续的。可以直接从读指针位置开始连续读取数据,如图
    在这里插入图片描述
  • 当读指针(tail) 在写指针前面的时候(head),表示数据跨越了缓冲区的末尾回到开头
    在这里插入图片描述

4. 当数据读写超出区域时

4.1 数据写入超出可写区域时

  1. 等待: 如果没有足够的空间写入新数据,可以等待读取更多的数据,释放空间
  2. 覆盖旧数据: 如果最新的数据比旧数据更重要,可以选择覆盖旧数据。这通常在数据流应用中使用,比如实时视频流处理。
  3. 拒绝写入: 直接拒绝写入操作,并可能返回一个错误,告诉调用者缓冲区已满。
  4. 动态扩容: 如果实现允许,可以动态增加缓冲区的大小以容纳更多数据。这可能需要重新分配内存和移动现有数据,从而增加复杂性和性能开销

假设一个大小为10的环形缓冲区,当前写指针在位置7,读指针在位置2,可写区域是3、4、5、6(4个位置),但你想写入5个字节的数据。
如果选择覆盖,那么从位置3开始的5个字节会写入,这将导致位置2的数据被覆盖(在实际应用中需要小心处理读写指针)。

4.2 数据读取超出可读区域

  1. 部分读取: 只读取可读区域内的数据,并返回实际读取的长度。
  2. 等待: 如果缓冲区中的数据不足,可以等待直到有足够的数据被写入。
  3. 返回错误: 如果必须一次性读取足够的数据,不足时返回错误。

5. 代码

主要的就是读取环形缓冲区部分的代码

5.1 定义数据结构

typedef struct Ring_buffer{
    unsigned char * buffer ;
    int buffer_size ;  
    int write_p ; 
    int read_p ; 
    int data_len ; 
}Ring_buffer, *Ring_buffer_p ;

5.2 对其初始化

// init the ring buffer 
int init_ring_buffer(Ring_buffer_p ring_buffer , int max_size)
{
    if(ring_buffer == NULL || max_size == 0)
    {
        return -1; 
    }
    memset(ring_buffer , 0 , sizeof(*ring_buffer)) ; 
    ring_buffer->buffer =(unsigned char *) malloc(max_size*sizeof(unsigned char)) ; 
    if(ring_buffer->buffer == NULL)
    { 
        printf("malloc the buffer fault\n") ; 
        return -1 ; 
    }
    ring_buffer->buffer_size = max_size ; 
    ring_buffer->write_p = 0 ; 
    ring_buffer->read_p = 0 ; 
    ring_buffer->data_len = 0 ;
    
    printf("init the ring buffer succesfull!\n") ; 
    return 0 ; 
}
}   

5.3 写环形缓冲区

参考上面的图


//write the ring buffer 
int write_ring_buffer(Ring_buffer_p ring_buffer , unsigned char* in_buf , int in_data_len)
{
    if(ring_buffer->data_len == ring_buffer->buffer_size)
    {
        printf("the ring buffer have been full\n") ; 
        return -1 ; 
    }
    else if(in_data_len == 0)
    {
        printf("no data need to write to the ring buffer\n") ; 
        return -1; 
    }

    // 1.计算剩余的空间
    int free_space  = 0 ; 
    if(ring_buffer->write_p >= ring_buffer->read_p)
    {//如果写指针在读指针的前面, 则剩余的空间分为两部分
        free_space =( ring_buffer->buffer_size - ring_buffer->write_p ) + (ring_buffer->read_p - 1); 
    }
    else
    {
        free_space = ring_buffer->read_p -1  - ring_buffer->write_p;
    }
    //2.计算实际写入的数据长度
    int need_write_len = in_data_len>free_space?free_space:in_data_len ; 
    printf("the auctual write data len is %d\n",need_write_len);

    int first_write_len = 0 ;
    int second_write_len = 0 ;
    if(ring_buffer->write_p >= ring_buffer->read_p) //分为两部分可以写入
    {
        /*1.先判断第一部分剩余的空间是否可以写完需要写的数据*/   
        first_write_len = min(ring_buffer->buffer_size - ring_buffer->write_p,need_write_len) ; 
        memcpy(ring_buffer->buffer+ring_buffer->write_p, in_buf,first_write_len);
        ring_buffer->write_p = (ring_buffer->write_p+first_write_len)%ring_buffer->buffer_size;
        ring_buffer->data_len += first_write_len;
        /*2.如果第一次写不完那么第二次进行写入*/
        if(need_write_len>first_write_len)
            {
                int second_write_len = need_write_len - first_write_len ; 
                memcpy(ring_buffer->buffer,in_buf+first_write_len,second_write_len );
                ring_buffer->write_p = (ring_buffer->write_p+first_write_len)%ring_buffer->buffer_size;
                ring_buffer->data_len += first_write_len;
            }
        }
    else
    {
        first_write_len = min(ring_buffer->read_p - ring_buffer->write_p -1 ,need_write_len); 
        memcpy(ring_buffer->buffer + ring_buffer->write_p,in_buf,first_write_len) ; 
        ring_buffer->write_p = (ring_buffer->write_p+first_write_len)%ring_buffer->buffer_size;
        ring_buffer->data_len += first_write_len;
    }
    return need_write_len  ; 
}

5.4 读环形缓冲区


//read the ring buffer 
int read_ring_buffer(Ring_buffer_p ring_buffer , unsigned char* out_buf , int out_data_len)
{
    if(out_data_len == 0 || ring_buffer->data_len==0)
    {
        printf("read data length is 0\n");
        return -1 ; 
    }
    
    int read_data_len ;
    read_data_len = out_data_len >ring_buffer->data_len ? ring_buffer->data_len:out_data_len;
    printf("coule read data length is %d\n",read_data_len);
    int first_read_len  = 0 ;
    int second_read_len  =0 ;

    if(ring_buffer->read_p >= ring_buffer->write_p)
    { //分为两部分进行读取
        first_read_len = ring_buffer->buffer_size - ring_buffer->read_p ; 
        memcpy(out_buf,ring_buffer->buffer + ring_buffer->read_p,first_read_len);
        ring_buffer->read_p = (ring_buffer->read_p+first_read_len)% ring_buffer->buffer_size ;
        ring_buffer->data_len = ring_buffer->data_len - first_read_len ; 
        printf("第一部分读取成功\n");
 
        if(read_data_len >  first_read_len)
        {
            second_read_len = read_data_len - first_read_len ; 
            memcpy(out_buf+first_read_len, ring_buffer->buffer,second_read_len);
            ring_buffer->read_p = second_read_len ;
            ring_buffer->data_len = ring_buffer->data_len - second_read_len ;
            printf("第二部分读取成功\n");
        }
    }
    else
    {//一次性全部读取
        memcpy(out_buf,ring_buffer->buffer+ring_buffer->read_p,read_data_len);
        ring_buffer->read_p = (ring_buffer->read_p+read_data_len)% ring_buffer->buffer_size ;
        ring_buffer->data_len = ring_buffer->data_len - read_data_len ; 
        printf("一次性读取成功\n");
    }
    return read_data_len ; 
}

5.5 测试

在这里插入图片描述

6 . 完整的代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<pthread.h>


#define min(a,b) ((a < b)?(a):(b))
#define MAX_RING_BUFFER_LEN 4

typedef struct Ring_buffer{
    unsigned char * buffer ;
    int buffer_size ;  
    int write_p ; 
    int read_p ; 
    int data_len ; 
    pthread_mutex_t lock ; 
}Ring_buffer, *Ring_buffer_p ;

// init the ring buffer 
int init_ring_buffer(Ring_buffer_p ring_buffer , int max_size)
{
    if(ring_buffer == NULL || max_size == 0)
    {
        return -1; 
    }
    memset(ring_buffer , 0 , sizeof(*ring_buffer)) ; 
    ring_buffer->buffer =(unsigned char *) malloc(max_size*sizeof(unsigned char)) ; 
    if(ring_buffer->buffer == NULL)
    { 
        printf("malloc the buffer fault\n") ; 
        return -1 ; 
    }
    ring_buffer->buffer_size = max_size ; 
    ring_buffer->write_p = 0 ; 
    ring_buffer->read_p = 0 ; 
    ring_buffer->data_len = 0 ;
    pthread_mutex_init(ring_buffer->lock , NULL) ; 

    printf("init the ring buffer succesfull!\n") ; 
    return 0 ; 
}

//write the ring buffer 
int write_ring_buffer(Ring_buffer_p ring_buffer , unsigned char* in_buf , int in_data_len)
{
    pthread_mutex_lock(ring_buffer->lock);
    if(ring_buffer->data_len == ring_buffer->buffer_size)
    {
        printf("the ring buffer have been full\n") ;
        pthread_mutex_unlock(ring_buffer->lock); 
        return -1 ; 
    }
    else if(in_data_len == 0)
    {
        printf("no data need to write to the ring buffer\n") ; 
        pthread_mutex_unlock(ring_buffer->lock);
        return -1; 
    }

    // 1.计算剩余的空间
    int free_space  = 0 ; 
    if(ring_buffer->write_p >= ring_buffer->read_p)
    {//如果写指针在读指针的前面, 则剩余的空间分为两部分
        free_space =( ring_buffer->buffer_size - ring_buffer->write_p ) + (ring_buffer->read_p - 1); 
    }
    else
    {
        free_space = ring_buffer->read_p -1  - ring_buffer->write_p;
    }
    //2.计算实际写入的数据长度
    int need_write_len = in_data_len>free_space?free_space:in_data_len ; 
    printf("the auctual write data len is %d\n",need_write_len);

    int first_write_len = 0 ;
    int second_write_len = 0 ;
    if(ring_buffer->write_p >= ring_buffer->read_p) //分为两部分可以写入
    {
        /*1.先判断第一部分剩余的空间是否可以写完需要写的数据*/   
        first_write_len = min(ring_buffer->buffer_size - ring_buffer->write_p,need_write_len) ; 
        memcpy(ring_buffer->buffer+ring_buffer->write_p, in_buf,first_write_len);
        ring_buffer->write_p = (ring_buffer->write_p+first_write_len)%ring_buffer->buffer_size;
        ring_buffer->data_len += first_write_len;
        /*2.如果第一次写不完那么第二次进行写入*/
        if(need_write_len>first_write_len)
            {
                int second_write_len = need_write_len - first_write_len ; 
                memcpy(ring_buffer->buffer,in_buf+first_write_len,second_write_len );
                ring_buffer->write_p = (ring_buffer->write_p+first_write_len)%ring_buffer->buffer_size;
                ring_buffer->data_len += first_write_len;
            }
        }
    else
    {
        first_write_len = min(ring_buffer->read_p - ring_buffer->write_p -1 ,need_write_len); 
        memcpy(ring_buffer->buffer + ring_buffer->write_p,in_buf,first_write_len) ; 
        ring_buffer->write_p = (ring_buffer->write_p+first_write_len)%ring_buffer->buffer_size;
        ring_buffer->data_len += first_write_len;
    }
    pthread_mutex_unlock(ring_buffer->lock);
}


//read the ring buffer 
int read_ring_buffer(Ring_buffer_p ring_buffer , unsigned char* out_buf , int out_data_len)
{
    pthread_mutex_lock(ring_buffer->lock);
    if(out_data_len == 0 || ring_buffer->data_len==0)
    {
        printf("read data length is 0\n");
        pthread_mutex_unlock(ring_buffer->lock);
        return -1 ; 
    }
    
    int read_data_len ;
    read_data_len = out_data_len >ring_buffer->data_len ? ring_buffer->data_len:out_data_len;
    printf("coule read data length is %d\n",read_data_len);
    int first_read_len  = 0 ;
    int second_read_len  =0 ;

    if(ring_buffer->read_p >= ring_buffer->write_p)
    { //分为两部分进行读取
        first_read_len = ring_buffer->buffer_size - ring_buffer->read_p ; 
        memcpy(out_buf,ring_buffer->buffer + ring_buffer->read_p,first_read_len);
        ring_buffer->read_p = (ring_buffer->read_p+first_read_len)% ring_buffer->buffer_size ;
        ring_buffer->data_len = ring_buffer->data_len - first_read_len ; 
        printf("第一部分读取成功\n");
 
        if(read_data_len >  first_read_len)
        {
            second_read_len = read_data_len - first_read_len ; 
            memcpy(out_buf+first_read_len, ring_buffer->buffer,second_read_len);
            ring_buffer->read_p = second_read_len ;
            ring_buffer->data_len = ring_buffer->data_len - second_read_len ;
            printf("第二部分读取成功\n");
        }
    }
    else
    {//一次性全部读取
        memcpy(out_buf,ring_buffer->buffer+ring_buffer->read_p,read_data_len);
        ring_buffer->read_p = (ring_buffer->read_p+read_data_len)% ring_buffer->buffer_size ;
        ring_buffer->data_len = ring_buffer->data_len - read_data_len ; 
        printf("一次性读取成功\n");
    }
    pthread_mutex_unlock(ring_buffer->lock);
    return read_data_len ; 
}



void printf_ring_buffer(Ring_buffer_p ring_buffer) 
{
    for(int i = ring_buffer->read_p ; i <= ring_buffer->data_len;++i)
    {
        printf("the ring_buffer[%d] data is : %d\n", i ,ring_buffer->buffer[i]);
    }
}


int main(int argc , char *argv[])
{
    int ret = 0 ; 
    Ring_buffer ring_buffer ; 
    init_ring_buffer(&ring_buffer , MAX_RING_BUFFER_LEN);
    unsigned  char in_buf[] = {2,5,3,4};
    for(int i = 0 ; i < sizeof(in_buf)/sizeof(in_buf[0]) ; ++i)
    {
	    printf("the in_buf[%d] data is: %d\n", i , in_buf[i]) ; 
    }
    ret = write_ring_buffer(&ring_buffer ,&in_buf,sizeof(in_buf)) ; 
    printf_ring_buffer(&ring_buffer) ; 

    unsigned char out_buf[2] ; 
    ret = read_ring_buffer(&ring_buffer,&out_buf,2);
    for(int i = 0 ; i < sizeof(out_buf)/sizeof(out_buf[0]);++i)
    {
        printf("the out_buf [%d] data is %d\n",i,out_buf[i]);
    }
    printf_ring_buffer(&ring_buffer) ; 
    return 0;
}
  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值