当前位置:网站首页>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;
}
边栏推荐
- Good bosses, please ask the flink CDC oracle to Doris, found that the CPU is unusual, a run down
- DHCP服务详解
- STM32-遥感数据处理
- Snake game bug analysis and function expansion
- QNX Hypervisor 2.2用户手册]10.2 vdev 8259
- ant-design的Select组件采用自定义后缀图标(suffixIcon属性)时,点击该自定义图标没有反应,不会展示下拉菜单的问题
- 工程制图复习题(带答案)
- Flask框架初学-05-命令管理Manager及数据库的使用
- 【指针内功修炼】深度剖析指针笔试题(三)
- 单片机C语言->的用法,和意思
猜你喜欢
参加Oracle OCP和MySQL OCP考试的学员怎样在VUE预约考试
Zabbix设置邮件告警+企业微信告警
Continuing to invest in product research and development, Dingdong Maicai wins in supply chain investment
Taurus.MVC WebAPI 入门开发教程1:框架下载环境配置与运行(含系列目录)。
html select tag assignment database query result
Development of Taurus. MVC WebAPI introductory tutorial 1: download environment configuration and operation framework (including series directory).
Priority_queue element as a pointer, the overloaded operators
MySQL高级-读写分离-分库分表
实例037:排序
共n级台阶,每次可以上1级或2级台阶,有多少种上法?
随机推荐
实例036:算素数
持续投入商品研发,叮咚买菜赢在了供应链投入上
The browser
MallBook联合人民交通出版社,推动驾培领域新发展,开启驾培智慧交易新生态
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
Promise 解决阻塞式同步,将异步变为同步
pytorch applied to MNIST handwritten font recognition
Big guys, it takes a long time to read mysql3 million single tables, what parameters can be discounted, or is there any way to hurry up
22/8/3(板子)树状dp板子+中国剩余定理+求组合数3,4+容斥原理
实例037:排序
云开发校园微社区微信小程序源码/二手交易/兼职交友微信小程序开源源码
DHCP服务详解
2022年T电梯修理考题及答案
LeetCode:899. 有序队列【思维题】
ant-design的Select组件采用自定义后缀图标(suffixIcon属性)时,点击该自定义图标没有反应,不会展示下拉菜单的问题
各位大佬好,麻烦问一下flink cdc oracle写入doris的时候,发现cpu异常,一下下跑
Countdown to 2 days, the "New Infrastructure of Cultural Digital Strategy and Ecological Construction of Cultural Art Chain" will kick off soon
自制蓝牙手机app控制stm8/stm32/C51板载LED
C程序编译和预定义详解
Security First: Tools You Need to Know to Implement DevSecOps Best Practices