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