目录
前言
缓冲区的主要目的是解决数据传输过程中的速度不匹配问题。在数据的发送方和接收方之间,通常存在着不同的速度和处理能力。发送方可能以较快的速度产生数据,而接收方可能以较慢的速度接收和处理数据。为了避免数据的丢失或丢失,需要一个中间存储区域来缓冲数据。
接下来我以QT 为例子讲一个通俗易懂的缓冲区,当然C语言也是可以实现的,这种思路可以参考。
一、缓冲区方法一
主要思想是通过 申请 缓冲空间和空间使用的标志位相互辅助而成,我们假设有一个需要缓冲的数据池,其中包含了多个缓冲区空间。初始时,所有缓冲区的标志位被设置为false,表示空闲状态。简单来说就是,通过标志位释放数据,增加数据,达到缓冲的效果。
二、初始化
2.1 初始化缓冲区
第一步需要申请一片空间,大小为SIZE_BOOL * SIZE_HD 这部分是缓冲区的空间
并申请标志位的空间,我们选择比较节省内存的方法用bool类型。
#define SIZE_BOOL 500
#define SIZE_HD 4
VCI_CAN_OBJ *G_frameBuffers = new VCI_CAN_OBJ[ SIZE_BOOL * SIZE_HD ];
bool * G_frame_flag = new bool[SIZE_BOOL];
VCI_CAN_OBJ是一个自定义的结构体,我这里是CAN的,在开发中只需要代替自己的内存就行了,要是没有结构体用 变量也可以。
typedef struct _VCI_CAN_OBJ{
UINT ID;
UINT TimeStamp;
BYTE TimeFlag;
BYTE SendType;
BYTE RemoteFlag;
BYTE ExternFlag;
BYTE DataLen;
BYTE Data[8];
BYTE Reserved[3]; ֡
}VCI_CAN_OBJ,*PVCI_CAN_OBJ;
2.2 头文件说明
以下就是这次的缓冲区的头文件,我做一下简单的说明。
FreeFrame_hd_Buffers :函数负责释放缓冲区。
Frame_hd_Buffer:函数负责返回指定位置的数据地址。
GetEmptyFrame_hd_Buffers:函数负责检查空闲位置缓冲区,并返回该位置。
G_idx:缓冲区使用当前的位置
G_mutexBuffer:互斥锁
通过以上说明可以看到,这种方法比较简洁,适合收藏,方便以后进行使用。
#ifndef FRAMEHDPOOL_H
#define FRAMEHDPOOL_H
#include <QObject>
#include <QMutex>
#include <QList>
#include "controlcan.h"
#define SIZE_BOOL 500
#define SIZE_HD 2
class framehdpool : public QObject
{
Q_OBJECT
public:
explicit framehdpool(QObject *parent = nullptr);
~framehdpool();
void FreeFrame_hd_Buffers(int idx);
PVCI_CAN_OBJ Frame_hd_Buffer(int idx);
PVCI_CAN_OBJ GetEmptyFrame_hd_Buffers(int *idx);
private:
int G_idx;
VCI_CAN_OBJ *G_frameBuffers;
bool *G_frame_flag;
QMutex G_mutexBuffer;
signals:
};
#endif // FRAMEHDPOOL_H
三、函数说明
3.1 初始化函数
初始化函数比较简单,申请了空间,初始一下默认值。
framehdpool::framehdpool(QObject *parent)
: QObject{parent}
{
G_idx = 0;
G_frameBuffers = new VCI_CAN_OBJ[ SIZE_BOOL * SIZE_HD ];
G_frame_flag = new bool[SIZE_BOOL];
if(G_frame_flag != nullptr) {
for(int i=0; i<SIZE_BOOL; i++)
G_frame_flag[i] = false;
}
}
3.2 释放函数
有申请当然就要有释放咯,这里在QT里面的析构函数就可以了,C语言的话需要手动释放一下。
framehdpool::~framehdpool()
{
if(G_frameBuffers != nullptr) {
delete [] G_frameBuffers;
G_frameBuffers = nullptr;
}
if(G_frame_flag != nullptr) {
delete [] G_frame_flag;
G_frame_flag = nullptr;
}
}
3.3 获取空闲缓冲区(重点)
这个函数主要负责,查找空闲的缓冲区位置,并返回空闲位置的地址。
说明:我们需要申请一个变量,传变量进去,通过指针把变量修改,从而得到空闲位置。例如下面这样,我们就可以得到两个关键数据,一个是frm缓冲区位置,还有一个是缓冲区的具体位置,这样我们在传递给处理函数的时候只需要传递这两个数据过去就可以了。
int index_num = -1;
PVCI_CAN_OBJ * frm = GetEmptyFrame_hd_Buffers(&index_num );
函数原型如下:(应该都能看懂,看不懂留言或者私信我,具体就不详细说了)
PVCI_CAN_OBJ framehdpool::GetEmptyFrame_hd_Buffers(int *idx)
{
PVCI_CAN_OBJ frm;
*idx = -1;
frm = nullptr;
if(G_frameBuffers == nullptr || G_frame_flag == nullptr)
return nullptr;
G_mutexBuffer.lock();
int i = 0;
while (i < SIZE_BOOL) {
if(!G_frame_flag[G_idx]) {
G_frame_flag[G_idx] = true;
*idx = G_idx;
frm = G_frameBuffers + G_idx * SIZE_HD;
break;
}
G_idx = (G_idx + 1) % SIZE_BOOL;
i ++;
}
G_mutexBuffer.unlock();
return frm;
}
3.4 释放缓冲区
这里的释放缓冲区并不是直接释放空间,而是对这片空间的标志进行释放,说明这片空间可以继续使用了。
函数原型:
//释放空间的标志位
void framehdpool::FreeFrame_hd_Buffers(int idx)
{
if(G_frameBuffers == nullptr || G_frame_flag == nullptr)
return;
G_mutexBuffer.lock();
G_frame_flag[idx] = false;
G_mutexBuffer.unlock();
}
3.5 获取指定位置数据
直接返回指定数据位置,原型比较简单,方便我们调用
函数原型:
PVCI_CAN_OBJ framehdpool::Frame_hd_Buffer(int idx)
{
return G_frameBuffers + ( idx * SIZE_HD );
}
四、总结
总结起来,本文介绍了一种基于标志位的缓冲区管理实现,通过申请缓冲空间和标志位的相互配合,实现了数据的缓冲效果。该方法可以在数据传输过程中平衡不同组件之间的速度差异,确保数据的顺利传输和处理。通过合理管理和利用缓冲区,可以提高程序的性能和效率。