环形缓冲区的实现原理与例程

在通信程序中,经常使用环形缓冲区作为数据结构来存放通信中发送和接收的数据。环形缓冲区是一个先进先出的循环缓冲区,可以向通信程序提供对缓冲区的互斥访问。

1、环形缓冲区的实现原理

环形缓冲区通常有一个读指针和一个写指针。读指针指向环形缓冲区中可读的数据,写指针指向环形缓冲区中可写的缓冲区。通过移动读指针和写指针就可以实现缓冲区的数据读取和写入。在通常情况下,环形缓冲区的读用户仅仅会影响读指针,而写用户仅仅会影响写指针。如果仅仅有一个读用户和一个写用户,那么不需要添加互斥保护机制就可以保证数据的正确性。如果有多个读写用户访问环形缓冲区,那么必须添加互斥保护机制来确保多个用户互斥访问环形缓冲区。

图1、图2和图3是一个环形缓冲区的运行示意图。图1是环形缓冲区的初始状态,可以看到读指针和写指针都指向第一个缓冲区处;图2是向环形缓冲区中添加了一个数据后的情况,可以看到写指针已经移动到数据块2的位置,而读指针没有移动;图3是环形缓冲区进行了读取和添加后的状态,可以看到环形缓冲区中已经添加了两个数据,已经读取了一个数据。

 

2、实例:环形缓冲区的实现

环形缓冲区是数据通信程序中使用最为广泛的数据结构之一,下面的代码,实现了一个环形缓冲区:

/*ringbuf .c*/
#include<stdio. h>
    #include<ctype. h>
#define NMAX 8
int iput = 0; /* 环形缓冲区的当前放入位置 */
int iget = 0; /* 缓冲区的当前取出位置 */
int n = 0; /* 环形缓冲区中的元素总数量 */
double buffer[NMAX];
/* 环形缓冲区的地址编号计算函数,如果到达唤醒缓冲区的尾部,将绕回到头部。
环形缓冲区的有效地址编号为:0到(NMAX-1)
*/
int addring (int i)
{
        return (i+1) == NMAX ? 0 : i+1;
}
/* 从环形缓冲区中取一个元素 */
double get(void)
{
int pos;
if (n>0){
                      Pos = iget;
                      iget = addring(iget);
                      n--;
                      return buffer[pos];
}
else {
printf(“Buffer is empty/n”);
return 0.0;
}
 
/* 向环形缓冲区中放入一个元素*/
void put(double z)
{
if (n<NMAX){
                      buffer[iput]=z;
                      iput = addring(iput);
                      n++;
}
else
printf(“Buffer is full/n”);
}
 
int main{void)
{
chat opera[5];
double z;
do {
printf(“Please input p|g|e?”);
scanf(“%s”, &opera);
               switch(tolower(opera[0])){
               case ‘p’: /* put */
                  printf(“Please input a float number?”);
                  scanf(“%lf”, &z);
                  put(z);
                  break;
case ‘g’: /* get */
                  z = get();
printf(“%8.2f from Buffer/n”, z);
break;
case ‘e’:
                  printf(“End/n”);
                  break;
default:
                  printf(“%s - Operation command error! /n”, opera);
}/* end switch */
}while(opera[0] != ’e’);
return 0;
}
 



项目需要,抽空了解了环形buffer,个人理解就是一个环形队列,先入先出,满足生产者-消费者模型。

环形buffer的好处:充分利用分配的内存,减少内存分配次数,从而减少内存碎片的产生。

环形buffer的实现,最重要的是记录入口和出口的指针,以及超过buffer长度的边界判断。

下面为环形buffer的简易实现代码:

其中rbuffer为环形buffer的定义,init_ring_buffer()、input_data()、output_data()分别实现了环形buffer的初始化、输入和输出数据。

main()函数中测试了环形buffer的上述功能。


<span style="font-family:Microsoft YaHei;font-size:14px;">#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//definition of ring buffer
typedef struct ring_buffer{
	char *buffer;      //buffer to store the data
	int in_pos;	   //flag to track the input pointer
	int out_pos;       //flag to track the output point
	int size;	   //buffer size
	int data_num;	   //the used buffer size
}rbuffer;

int init_ring_buffer(rbuffer * rbuf, int size) //init buffer
{
	rbuf->buffer = (char *)malloc(size * sizeof(char));
	if(rbuf->buffer == NULL){
		printf("Cannot allocte memory!\n");
		exit(1);
	}

	rbuf->in_pos = 0;
	rbuf->out_pos = 0;
	rbuf->data_num = 0
	rbuf->size = size;
	
	return 0;
}

rbuffer *input_data(rbuffer *rbuf, char *buf, int len) //input data
{	
	if(len <= 0)
		return rbuf;

	if(len <= rbuf->size - rbuf->in_pos){
		memcpy(rbuf->buffer + rbuf->in_pos, buf, len);
		rbuf->in_pos = (rbuf->in_pos + len) % rbuf->size;
	}
	else{
		memcpy(rbuf->buffer + rbuf->in_pos, buf, rbuf->size - rbuf->in_pos);
		memcpy(rbuf->buffer, buf + rbuf->size - rbuf->in_pos, len - (rbuf->size - rbuf->in_pos));
		rbuf->in_pos = len - (rbuf->size - rbuf->in_pos);
	}

	rbuf->data_num += len;

	return rbuf;
}

rbuffer *output_data(rbuffer *rbuf, char *buf, int len)  //out put data
{
	if(len <= 0)
		return rbuf;

	if(len >= rbuf->data_num){
		printf("No enough data!\n");
		return rbuf;
	}
	if(len < rbuf->size - rbuf->out_pos){
		memcpy(buf, rbuf->buffer + rbuf->out_pos, len);
		rbuf->out_pos = (rbuf->out_pos + len) % rbuf->size

	}	
	else{
		memcpy(buf, rbuf->buffer + rbuf->out_pos, rbuf->size - rbuf->out_pos);
		memcpy(buf +  rbuf->size - rbuf->out_pos, rbuf->buffer, len - (rbuf->size - rbuf->out_pos));
		rbuf->out_pos = len - rbuf->out_pos;
	}

	rbuf->data_num -= len;

	return rbuf;
}

void show_buf(char *buf, int num)
{
	int i;
	for(i = 0; i < num; i++){
		printf("%d  ", buf[i]);
	}
	printf("\n");
}

int main()
{
	int ret;
	char testbuf1[3] = {1, 2, 3};
	char testbuf2[5] = {1, 2, 3, 4, 5};
	char outbuf[5];
	rbuffer *mbuf;
	
	mbuf = (rbuffer *)malloc(sizeof(rbuffer));	
	if(ret = init_ring_buffer(mbuf, 5) !=0){
		printf("malloc error\n");
		return 1;
	}

	mbuf = input_data(mbuf, testbuf1, 2 );
	show_buf(mbuf->buffer, 5);
	
	mbuf = input_data(mbuf, testbuf2, 5 );
	show_buf(mbuf->buffer, 5);

	mbuf = output_data(mbuf, outbuf, 2);
	show_buf(outbuf,2);	
	mbuf = output_data(mbuf, outbuf, 2);
	show_buf(outbuf,2);	
	mbuf = output_data(mbuf, outbuf, 4);
	show_buf(outbuf,4);	

	return 0;
}</span>
  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值