当前位置:网站首页>C语言--环形缓存区
C语言--环形缓存区
2022-08-04 02:28:00 【Coder_貔貅】
环形缓存区工作原理
环形缓冲区是固定大小的缓冲区,工作原理就像内存是连续的且可循环。在生成和使用内存时,不需要将原来的数据全部清理掉,只要调整head/tail指针即可。当添加数据时,head指针前进。当使用数据时,tail指针向前移动。当到达缓冲区的尾部时,指针又回到缓冲区的起始位置。

优势:当有大量数据但不需要全部存储的情况下,计算机在处理数据时会先处理先来的,处理完之后会把数据释放掉,再继续处理下一个。那么已经处理的数据的内存就会被浪费掉。因为后来的数据只能往后排队,如果将剩余的数据都往前移动一次,效率便会大大降低。因此环形队列就出现了。核心是申请一段内存,通过特殊方法让其首尾相连,形成一个闭环的内存地址。这样既可以继续处理源源不断的数据,又不用再去申请新的内存空间暂存新的数据,效率大大提高。
劣势:环形缓冲区最重要的一个特点是写的速度和读的速度匹配性问题,环形缓冲区一般是将数据先写入缓冲区内,然后有个写的指针位置,但是不能超过读的位置,因为数据还未被读取,便写入数据,就会造成数据还未被读取便被新的数据覆盖,造成数据的丢失。读数据同样原理,读的指针不能超过写的位置,这样就会读到之前读过的数据,造成数据的重复。空间如果设置的太大,会造成内存的浪费,有内存一直处于空闲状态,如果空间设置到的太小,可能会造成读的速度快于写的速度,导致读的过程中会有短暂的等待时间,造成效率不是最高。
1、写入数据<缓冲区

2、写入数据>缓冲区

代码:
#include "RingBuffer.h"
static UINT16 validlen; //已使用的数据长度
static UINT8* pHead = NULL; //环形缓冲区首地址
static UINT8* pTail = NULL; //环形缓存区尾地址
static UINT8* pValid = NULL; //已使用缓冲区的首地址
static UINT8* pValidTail = NULL; //已使用缓冲区的尾地址
//malloc申请空间
void initRingbuffer(void)
{
if(pHead == NULL)
{
pHead = (char*) malloc(BUFFER_SIZE);
}
pValid = pValidTail = pHead;
pTail = pHead + BUFFER_SIZE;
validlen = 0;
}
//释放环形缓冲区
void releaseRingbuffer(void)
{
if(pHead != NULL)
free(pHead);
pHead = NULL;
}
/*************************************************************/
/******功能:初始化指定的环形缓冲区 *****/
/******param:@buffer:定义静态缓冲区数组的首地址
param:@size:该缓冲区的大小 ******/
/************************************************************/
void InitRingBuffer(UINT8* buffer, UINT16 size)
{
if(pHead == NULL)
{
pHead = buffer;
}
pValid = pValidTail = pHead;
pTail = pHead + size;
validlen = 0;
}
/***********************************************************/
/******功能:向缓冲区写入数据 *****/
/******param:@buffer 写入的数据指针
@len 写入的数据长度 ******/
/******return:-1 写入的数据长度过大 -2:缓冲区未初始化 *****/
/***********************************************************/
int writeRingbuffer(UINT8* buffer, UINT32 len)
{
UINT16 len1, len2, movelen;
if(len > BUFFER_SIZE)
{
return -1;
}
if(pHead == NULL)
{
return -2;
}
assert(buffer);
//将要写入的数据copy到pVaildTaill处
if(pValidTail+len > pTail)
{
len1 = pTail - pValidTail; //放到尾部
len2 = len - len1; //尾部放不下的位置,从头开始放
memcpy(pValidTail, buffer, len1);
memcpy(pHead, buffer + len1, len2);
pValidTail = pHead + len2; //新的有效数据
}else
{
memcpy(pValidTail, buffer, len);
pValidTail += len; //新的有效数据区结尾
}
//重新计算已使用区的起始位置
if(validlen + len > BUFFER_SIZE)
{
movelen = validlen + len - BUFFER_SIZE;
if(pValid + movelen > pTail) //需要分成两段
{
len1 = pTail - pValid;
len2 = movelen - len1;
pValid = pHead + len2;
}else
{
pValid += movelen;
}
validlen = BUFFER_SIZE;
}else
{
validlen += len;
}
return 0;
}
/*************************************************************/
/******功能:从缓冲区读取指定长度的数据 *****/
/******param:@buffer 接收读取数据的指针
@length 读取的数据长度 ******/
/******return:-1 缓冲区未初始化 >0:读取的有效数据大小 *****/
/*************************************************************/
int readRingbuffer(UINT8* buffer, UINT32 len)
{
UINT16 len1, len2;
if(pHead == NULL)
{
return -1;
}
assert(buffer);
if(len > validlen)
{
len = validlen;
}
if(validlen == 0)
{
return 0;
}
if(pValid + len > pTail) //需要分成两段copy
{
len1 = pTail - pValid;
len2 = len - len1;
memcpy(buffer, pValid, len1); //第一段
memcpy(buffer + len1, pHead, len2); //第二段 ,绕到整个存储区的开头
pValid = pHead + len2; //更新已使用缓冲区的起始
}else
{
memcpy(buffer, pValid, len);
pValid += len; //更新已使用缓冲区的起始
}
validlen -= len; //更新已使用缓冲区的长度
return len;
}
/*************************************************************/
/******功能:获取已使用的缓冲区数据长度 *****/
/******param:void ******/
/******return:已使用缓冲区的数据长度 *****/
/************************************************************/
UINT32 getRingbufferValidLen(void)
{
return validlen;
}
边栏推荐
猜你喜欢

C program compilation and predefined detailed explanation

云开发校园微社区微信小程序源码/二手交易/兼职交友微信小程序开源源码

Download install and create/run project for HBuilderX

esp32发布机器人电池电压到ros2(micro-ros+CoCube)

Flink原理流程图简单记录

esp32 releases robot battery voltage to ros2 (micro-ros+CoCube)

Example 039: Inserting elements into an ordered list

Engineering drawing review questions (with answers)

HBuilderX的下载安装和创建/运行项目

mpf5_定价Bond_yield curve_Spot coupon_duration_有效利率_连续复利_远期_Vasicek短期_CIR模型Derivatives_Tridiagonal_ppf
随机推荐
2022广东省安全员A证第三批(主要负责人)考试题库及模拟考试
【Playwright测试教程】5分钟上手
ant-design的Select组件采用自定义后缀图标(suffixIcon属性)时,点击该自定义图标没有反应,不会展示下拉菜单的问题
实例041:类的方法与变量
cdh6.x 集成spark-sql
Qt中对象树的机制介绍以及底层实现,各种结果分析:(以及自己写容易犯错的点)
在更一般意义上验算移位距离和假设
Engineering drawing review questions (with answers)
Sky map coordinate system to Gaode coordinate system WGS84 to GCJ02
Parquet encoding
Example 037: Sorting
自制蓝牙手机app控制stm8/stm32/C51板载LED
LeetCode:899. 有序队列【思维题】
flinkcdc 消费 mysql binlog 没有 sqltype=delete 的数据是什么原
Zabbix set up email alert + enterprise WeChat alert
Utilities of Ruineng Micrometer Chip RN2026
Parquet encoding
单片机C语言->的用法,和意思
织梦内核电动伸缩门卷闸门门业公司网站模板 带手机版【站长亲测】
董明珠直播时冷脸离场,员工频犯低级错误,自家产品没人能弄明白