环形缓冲区(ring buffer),环形队列(ring queue) 原理

环形缓冲区(ring buffer),环形队列(ring queue) 多用于2个线程之间传递数据,是标准的先入先出(FIFO)模型。一般来说,对于多线程共享数据,需要使用mutex来同步,这样共享数据才不至于发生不可预测的修改/读取,然而,mutex的使用也带来了额外的系统开销,ring buffer/queue 的引入,就是为了有效地解决这个问题,因其特殊的结构及算法,可以用于2个线程中共享数据的同步,而且必须遵循A线程push in,B线程pull out的原则。采用这个机制另外一个用处是A push完数据后可以马上接收另外一个数据,当输入数据快速时不容易造成数据阻塞而丢包.

线程 A                       媒介                        线程 B
data_in --------> ring buffer/queue -------> data out


=============RingBuffer完整C测试代码[单元素]==========

#include <stdio.h>
#include <stdlib.h>
 
typedef struct TAG_RING_BUFFER
{
    int wrPos;
    int rdPos;
    int maxCount;
	int remainCnt;
    char *buffer;
	
} TagRingBuffer;
 
TagRingBuffer* ringBuffer_init(int size)
{
	 //Note: (size-1) is full!!
	TagRingBuffer * rb;
    rb = (TagRingBuffer*)malloc(sizeof(TagRingBuffer));
    if( rb == NULL)
    {
        return NULL;
    }
    rb->buffer = (char*)malloc( size );
    if( rb->buffer == NULL )
    {
        return 0;
    }
	rb->maxCount = size;
	rb->wrPos = 0;
	rb->rdPos = 0;
	rb->remainCnt = 0;
    return rb;
}
 
void ringBuffer_free(TagRingBuffer* rb)
{
	if( rb )
	{
		if(rb-> buffer)
		{
			free( rb-> buffer );
		}
		free( rb );
	}
}
 
int is_ringBuffer_full(TagRingBuffer* rb)
{
  //Note:(MAXCOUNT-1) is full!!
	if( ( (rb->wrPos)+1)%(rb->maxCount) == rb->rdPos )
	 return 1;
 
    return 0;
}
 
int is_ringBuffer_empty(TagRingBuffer* rb)
{
	if( (rb->wrPos) == rb->rdPos ){
	 return 1;
	}
 
    return 0;
}
 
int ringBuffer_pop(TagRingBuffer* rb,char *ch)
{  //read
	if( is_ringBuffer_empty(rb))
	{
		return 0;
	}
	*ch = rb->buffer[ rb->rdPos ];
	rb->rdPos =  (rb->rdPos +1)%rb->maxCount;
	rb->remainCnt --;
	return 1;
}
 
int ringBuffer_push(TagRingBuffer* rb,char ch)
{  //write
	if( is_ringBuffer_full(rb))
	{
		return 0;
	}
	rb->buffer[ rb->wrPos ] = ch;	
	rb->wrPos =  (rb->wrPos +1)%(rb->maxCount);
	rb->remainCnt++;
	return 1;
}

int ringBuffer_getRemainCnt(TagRingBuffer* rb)
{
	return rb->remainCnt;
}
 
 //RingBuffer 测试[单元素]
void main()
{
 
	printf("----C_BuildTime: %s----\r\n", __TIME__ );
	
   TagRingBuffer *rb ;
   char ch;
   int retn = 1;
   int remain = 0;
   
   rb = ringBuffer_init(5);
 
   ringBuffer_push(rb,1);
   ringBuffer_push(rb,3);  
   ringBuffer_push(rb,5); 
   ringBuffer_push(rb,7);//effect data
   
   ringBuffer_push(rb,9); //buffer is full
   ringBuffer_push(rb,11);
   ringBuffer_push(rb,13);
   ringBuffer_push(rb,15);
   
   
   for(int i=0;i<10;i++)
   { //测试超出ringbuffer范围的数据
	 ch = 0;
	 remain = ringBuffer_getRemainCnt(rb);
	 retn = ringBuffer_pop(rb,&ch);	 
	 printf("[%d] out_data=(%d),remain=%d,ret=%d.\n",i,ch,remain,retn  );   
   }	
}

=============RingQueue完整C测试代码[多元素]==========

#include <stdio.h>
#include <stdlib.h>
 
typedef struct TAG_RING_QUEUE
{
    int wrPos;
    int rdPos;
    int maxCount;
	int remainCnt;
    long *buffer;//storage address
	
} TagRingQueue;
 
TagRingQueue* ringQueue_init(int size)
{
	 //Note: (size-1) is full!!
	TagRingQueue * rb;
    rb = (TagRingQueue*)malloc(sizeof(TagRingQueue));
    if( rb == NULL)
    {
        return NULL;
    }
    rb->buffer = (long*)malloc( size* sizeof(long) );
    if( rb->buffer == NULL )
    {
        return 0;
    }
	rb->maxCount = size;
	rb->wrPos = 0;
	rb->rdPos = 0;
	rb->remainCnt = 0;
    return rb;
}
 
void ringQueue_free(TagRingQueue* rb)
{
	if( rb )
	{
		if(rb-> buffer)
		{
			free( rb-> buffer );
		}
		free( rb );
	}
}
 
int is_ringQueue_full(TagRingQueue* rb)
{
  //Note:(MAXCOUNT-1) is full!!
	if( ( (rb->wrPos)+1)%(rb->maxCount) == rb->rdPos )
	 return 1;
 
    return 0;
}
 
int is_ringQueue_empty(TagRingQueue* rb)
{
	if( (rb->wrPos) == rb->rdPos ){
	 return 1;
	}
 
    return 0;
}
 
//注意:data第一字节存数据长度,后面的数据才是本体 
//注意使用完后必须释放指针.
char* ringQueue_pop(TagRingQueue* rb,short *lenOut)
{  //read
    char *buff_pt = NULL;
	*lenOut = 0;
	if( is_ringQueue_empty(rb))
	{
		return NULL;
	}
	buff_pt = (char*)rb->buffer[ rb->rdPos ];
	rb->rdPos =  (rb->rdPos +1)%rb->maxCount;
	rb->remainCnt --;
	if( buff_pt != NULL)
	{
		*lenOut = *buff_pt;
		buff_pt++;
	}	
	return buff_pt;//must free after use!
}
 
//注意:data第一字节存数据长度,后面的数据才是本体
int ringQueue_push(TagRingQueue* rb,char *data,short len)
{  //write
    char *buff_pt = NULL;
	if( is_ringQueue_full(rb))
	{
		return 0;
	}
	buff_pt = (char*)malloc(len+1);
	if( buff_pt == NULL )
	{
		return -1;//no mem
	}
	buff_pt[0] = len; //data第一字节存数据长度
	memcpy(buff_pt+1,data,len);
	rb->buffer[ rb->wrPos ] = (long)buff_pt;	
	rb->wrPos =  (rb->wrPos +1)%(rb->maxCount);
	rb->remainCnt++;
	return 1;
}

int ringQueue_getRemainCnt(TagRingQueue* rb)
{
	return rb->remainCnt;
}
 
 
void dump_hex(char *infoStr,char *buf,int len)
{
	printf("%s(%d)",infoStr,len);
	for(int i=0;i<len;i++)
	{
		printf("%02X ",(unsigned char)buf[i]);
	}
	printf("\n");
} 
 
//RingQueue 测试 [多元素]
void main()
{
	printf("----C_BuildTime: %s----\r\n", __TIME__ );
	
   TagRingQueue *rb ;
   char data[50];   
   
   rb = ringQueue_init(5);//MAXCOUNT-1=4
 
   char rawDat[]={0x39,0x38,0x03,0x00,0x35,0x00,0x00};
   ringQueue_push(rb,rawDat,sizeof(rawDat)); //test raw data

   sprintf(data,"English");
   ringQueue_push(rb,data,strlen(data)+1);
   
   sprintf(data,"USA");
   ringQueue_push(rb,data,strlen(data)+1);    
   
   sprintf(data,"Japan");
   ringQueue_push(rb,data,strlen(data)+1);     
   
   sprintf(data,"India");
   ringQueue_push(rb,data,strlen(data)+1);   

   sprintf(data,"Yemen");
   ringQueue_push(rb,data,strlen(data)+1);   


   char* datOut = NULL;
   short lenOut = 0;

   
   for(int i=0;i<10;i++)
   { //测试超出ringQueue范围的数据
        datOut = ringQueue_pop(rb,&lenOut);
        printf("\n[%d] len_out=%d,data=[%s].",i,lenOut,datOut);
		dump_hex("HEX",datOut,lenOut);
		free(datOut);//must free after use
   }	
}

 

  • 2
    点赞
  • 8
    收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论 2

打赏作者

wabil

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值