当前位置:网站首页>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;
}
边栏推荐
- 云开发旅游打卡广场微信小程序源码(含视频教程)
- 自制蓝牙手机app控制stm8/stm32/C51板载LED
- TOML配置文件格式,YAML最有力的竞争者
- Web APIs BOM - operating browser: swiper plug-in
- 第13章 网络安全漏洞防护技术原理与应用
- 2022.8.3-----leetcode.899
- Rongyun "Audio and Video Architecture Practice" technical session [complete PPT included]
- Ant - the design of the Select component using a custom icon (suffixIcon attribute) suffixes, click on the custom ICONS have no reaction, will not display the drop-down menu
- pytorch应用于MNIST手写字体识别
- FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
猜你喜欢
Continuing to invest in product research and development, Dingdong Maicai wins in supply chain investment
云开发校园微社区微信小程序源码/二手交易/兼职交友微信小程序开源源码
安全至上:落地DevSecOps最佳实践你不得不知道的工具
Flask Framework Beginner-06-Add, Delete, Modify and Check the Database
priority_queue元素为指针时,重载运算符失效
参加Oracle OCP和MySQL OCP考试的学员怎样在VUE预约考试
2022年T电梯修理考题及答案
Example: 036 is a prime number
Instance, 038: the sum of the diagonal matrix
Continuing to invest in product research and development, Dingdong Maicai wins in supply chain investment
随机推荐
In the season of going overseas, the localization of Internet tips for going overseas
【指针内功修炼】深度剖析指针笔试题(三)
香港服务器有哪些常用的型号
STM8S105K4T6------串口发送和接收
小甲鱼汇编笔记
2022G1工业锅炉司炉考试练习题及模拟考试
Day13 Postman的使用
Use of lombok annotation @RequiredArgsConstructor
web端动效 lottie-web 使用
Taurus.MVC WebAPI 入门开发教程1:框架下载环境配置与运行(含系列目录)。
ant-design的Select组件采用自定义后缀图标(suffixIcon属性)时,点击该自定义图标没有反应,不会展示下拉菜单的问题
2022广东省安全员A证第三批(主要负责人)考试题库及模拟考试
FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed
【Playwright测试教程】5分钟上手
网页三维虚拟展厅为接入元宇宙平台做基础
Instance, 038: the sum of the diagonal matrix
What is SVN (Subversion)?
0.1 前言
QNX Hypervisor] 10.2 vdev 8259 2.2 user manual
实例039:有序列表插入元素