c语言图文详解 实现ringbuff 源码详解

一 什么是ringbuff

ringbuff是环形buff,是buff缓存的一种,可以用来存放程序运行过程的暂时数据。一般的buff即是一个数组,而环形buff就是将数组的头和尾链接起来的数组。
老规矩,源码先放这:
码云:https://gitee.com/killerp/mylib.git

1,ringbuff的优点

ringbuff比普通的buff使用更加高效灵活,可以边读数据边写数据。

二 ringbuff的实现

一个ringbuff的实现至少需要以下四个功能:

  • 创建ringbuff
  • 数据写入ringbuff
  • 从ringbuff读取数据
  • 删除ringbuff

0,ringbuff结构体

typedef struct RingBuff *RingBuff_handle;

//ringbuff结构体
struct RingBuff
{
	unsigned char *source;	//ringbuff的头部
	unsigned char *tail;	//尾部
	unsigned char *write;	//写指针
	unsigned char *read;	//读指针
	int size;	//ringbuff总长度
	int writed_size;	//写入数据的长度
	int remain_size;	//剩余空间
	
};

如下图所示,一般一个ringbuff创建后,size,source和tail指针是固定的。当write移动到tail时,如果有数据需要写入,write会移动到source处继续写入,但是write不会覆盖掉未被read指针读取的数据。当read移动到tail时同样,如果需要继续读取数据,会移动到source继续读取。注意!write移动的长度不能超过remain_size(剩余空间);read移动的长度部能超过write_size(已写入长度);基本的工作原理就是这样。
在这里插入图片描述

1,ringbuff的创建

ringbuff的创建实际上是调用malloc();实现动态内存分配,内存的大小由用户输入参数决定,分配的内存的地址指针会赋值给source,同时计算tail的指针,第一次创建也会初始化ringbuff的其他成员。一般的size最好比一次读写的长度大几倍。

/*

* 创建一个ringbuff 用户定义字节大小
*/
RingBuff_handle createRingBuff(int totalsize)
{
	RingBuff_handle ringbuff;
	ringbuff = malloc(sizeof(struct RingBuff));
	ringbuff->source = malloc(totalsize);
	if(ringbuff->source !=NULL)
	{
		LOGI("create ringbuff success!");
	}
	
	ringbuff->write = ringbuff->source;
	ringbuff->read = ringbuff->source;
	ringbuff->writed_size = 0;
	ringbuff->tail = ringbuff->source + totalsize;
	ringbuff->size = totalsize;
	ringbuff->remain_size = totalsize;
	return ringbuff;
	
}

2,计算已写入数据的长度

计算writed_size的大小非常关键。这里先给出伪代码计算公式:

writed_size = (size +(write - read)%size

理解它需要先了解ringbuff的读写指针的两种位置关系:

  • 写指针在读指针前面
  • 读指针在写指针前面
    在这里插入图片描述代码实现:
/*
* 获得已写入数据的字节
*/
int getRingBuffWritedSize(RingBuff_handle handle)
{
	handle->writed_size = (handle->size + (handle->write - handle->read)) % handle->size;
	LOGI("writed_size = %d",handle->writed_size);
	return handle->writed_size;
}

3,数据写入ringbuff

在读写数据的处理上都需要分以上两种情况处理。

/*
* 写入ringbuff handle 数据 数据字节长度
*/
int writeRingBuff(RingBuff_handle handle,unsigned char *data,int size)
{
	if(handle->source == NULL ||handle == NULL)
	{
		LOGE("ringbuff has not been init");
		return 0;
	}
	//检查剩余内存是否足够
	if(handle->remain_size > size)
	{
		//写指针在读指针前
		if(handle->write - handle->read >0)
		{
			int writebytes = handle->tail - handle->write - size;
			//写入的数据小于写指针到内存尾部
			if(writebytes >= 0)
			{
				memcpy(handle->write,data,size);
				handle->write += size;
		
			}
			else //写入的数据大于写指针到内存尾部,需要从头部继续写入
			{
				//写入数据到尾部
				memcpy(handle->write,data,handle->tail - handle->write);
				data += handle->tail - handle->write;
				writebytes = abs(writebytes);
				//从头部继续写入剩余数据
				memcpy(handle->source,data,writebytes);
				handle->write = handle->source +  writebytes;
			
			}
		}
		else	//读指针在写指针前
		{
			memcpy(handle->write,data,size);
			handle->write += size;
			
		}
		LOGI("write success");
		//更新参数
		getRingBuffRemainSize(handle);
		return 1;	
	}
	else
	{
		LOGE("write fail");
		return 0;
	}
	
}

4,读取ringbuff数据

读取数据也要区别指针的位置情况。读取与写入逻辑上差别不大。

/*
* 读取ringbuff数据 
*/
int readRingBuff(RingBuff_handle handle,unsigned char *data,int size)
{
	if(handle->source == NULL ||handle == NULL)
	{
		LOGE("ringbuff has not been init");
		return 0;
	}
	if(data == NULL)
	{
		malloc(sizeof(unsigned char));
	}

	//要读取的数据少于已经写入的数据
	if(handle->writed_size >= size)
	{
		//写指针在读指针前
		if(handle->write - handle->read >0)
		{
			memcpy(data,handle->read,size);
			handle->read += size;
		}
		else	//读指针在写指针前
		{
			int readbytes = handle->tail - handle->read - size;
			
			//读取,不用从头读
			if(readbytes > 0)
			{
				memcpy(data,handle->read,size);
				handle->read += size;
			}
			else 	//需要从头读
			{
				memcpy(data,handle->read,handle->tail - handle->read);
				readbytes = abs(readbytes);
				data += handle->tail - handle->read;
				memcpy(data,handle->source,readbytes);
				handle->read = handle->source + readbytes;
			}
		}
		
		LOGI("read success");
		//更新参数
		getRingBuffRemainSize(handle);
		return 1;
	}
	else
	{
		LOGE("read fail");
		return 0;
	}
	
}

5,删除ringbuff

删除函数其实是调用free();函数释放由malloc();分配的内存。需要检查指针是否空。

/*
* 删除ringbuff
*/
int deleteRingBuff(RingBuff_handle handle)
{
	//需要判断指针是否空,否则free()会出错
	if(handle == NULL ||handle->source == NULL)
	{
		LOGE("free fail");
		return 0;
	}
	free(handle->source);
	free(handle);
	LOGI("free ringbuff success");
	return 1;
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44821644/article/details/108274738