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

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

    当然基于这个模型还可以新增一些功能,如在push前加锁,就可以让多个线程来push数据。

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

===============RingBuffer完整Python测试代码======================= 

class RingBuffer:
    def __init__(self, size_max):
        self.max = size_max + 1
        self.data = [None] * self.max
        self.wrPos = 0
        self.rdPos = 0

    def is_ringbuffer_full(self):
        if (self.wrPos + 1) % self.max == self.rdPos:
            return 1
        else:
            return 0

    def is_ringbuffer_empty(self):
        if self.wrPos == self.rdPos:
            return 1
        else:
            return 0

    # pop up data from rb
    def get(self):
        if self.is_ringbuffer_empty():
            return None
        ret = self.data[self.rdPos]
        self.rdPos = (self.rdPos + 1) % self.max
        return ret

    # push data to rb
    def append(self, item):
        if self.is_ringbuffer_full():
            return 0
        self.data[self.wrPos] = item
        self.wrPos = (self.wrPos + 1) % self.max
        return 1


if __name__ == "__main__":
    rb = RingBuffer(5)
    rb.append(1)
    rb.append(2)
    rb.append(3)
    rb.append(4)
    rb.append(5)
    rb.append(6)
    print(rb.get())  # 输出1
    print(rb.get())  # 输出2
    print(rb.get())  # 输出3
    print(rb.get())  # 输出4
    print(rb.get())  # 输出5
    print(rb.get())  # 输出None,因为buffer已经清空

    rb.append("Chinese")  # 重新push
    rb.append("English")
    rb.append("Franch")
    rb.append([10, 20, 30])

    print(rb.get())  # 输出 Chinse
    print(rb.get())  # 输出 English
    print(rb.get())  # 输出 Franch
    print(rb.get())  # 输出 [10,20,30]
    print(rb.get())  # 输出None,因为buffer已经清空


=============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>
#include <string.h>
 
typedef struct TAG_RING_QUEUE
{
    int wrPos;
    int rdPos;
    int maxCount;
	int remainCnt;
    char**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 = (char**)malloc( size* sizeof(char**) );
    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 );
	}
}

//首字节为长度数据
void ringQueue_free_pt(char*datPoint)
{
    if( (datPoint!=NULL) && ((datPoint-1)!=NULL))
    {
        free(datPoint-1);
    }
}
 
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前1节存数据长度,后面的数据才是本体 
//注意使用完后必须释放指针.
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! NOTE: free(buff_pt-1)
}
 
//注意:data前1字节存数据长度,后面的数据才是本体
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 ] = 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);
        ringQueue_free_pt(datOut);//must free after use!!
 
   }	
}

//PS:由于部分51单片机没有malloc函数库,固采用数组方案平替。

//=================51单片机的ringbuffer方案====================

#include <stdio.h>
#include <stdlib.h>

typedef struct TAG_RING_BUFFER
{
    int wrPos;
    int rdPos;
    int maxCount;
	int remainCnt;
    char *buffer;
	
} TagRingBuffer;

void ringBuffer_init(TagRingBuffer *rb, int size, char *new_buffer)
{
	// Note: (size-1) is full!!
	if (rb == NULL)
	{
		return;
	}
	rb->buffer = new_buffer;
	if (rb->buffer == NULL)
	{
		return;
	}
	rb->maxCount = size;
	rb->wrPos = 0;
	rb->rdPos = 0;
	rb->remainCnt = 0;
	return;
}

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;
}

void dump_hex(char *data, int len, char *info)
{
	printf("%s(%d) ", info, len);
	for (size_t i = 0; i < len; i++)
	{
		printf("%02x ", (unsigned char)data[i]);
	}
	printf("\n");
}

// RingBuffer 测试[单元素],适用于8051等单片机
void main()
{

	TagRingBuffer rb1;
	TagRingBuffer rb2;
	char i, ch;
	int retn = 1;
	int remain = 0;
	static char new_buffer1[5] = {0};
    static char new_buffer2[8] = {0};

	ringBuffer_init(&rb1, sizeof(new_buffer1), new_buffer1);
	ringBuffer_init(&rb2, sizeof(new_buffer2), new_buffer2);

	
	ringBuffer_push(&rb1, 1);
	ringBuffer_push(&rb1, 3);
	ringBuffer_push(&rb1, 5);
	ringBuffer_push(&rb1, 7); // effect data
	ringBuffer_push(&rb1, 9); // buffer is full
	ringBuffer_push(&rb1, 11);
	ringBuffer_push(&rb1, 13);

	ringBuffer_push(&rb2, 101);
	ringBuffer_push(&rb2, 103);
	ringBuffer_push(&rb2, 105);
	ringBuffer_push(&rb2, 107);  
	ringBuffer_push(&rb2, 109);  
	ringBuffer_push(&rb2, 101);	
    ringBuffer_push(&rb2, 103);	



	printf("==========BUILD:%s %s=========\n", __TIME__, __DATE__);
	for (i = 0; i < 10; i++)
	{ // 测试超出ringbuffer范围的数据
		ch = 0;
		remain = ringBuffer_getRemainCnt(&rb1);
		retn = ringBuffer_pop(&rb1, &ch);
		printf("[%d] rb1_out_data=(%d),remain=%d,ret=%d.\n", i, ch, remain, retn);
	}
	printf("=============================================\n");	
	for (i = 0; i < 10; i++)
	{ // 测试超出ringbuffer范围的数据
		ch = 0;
		remain = ringBuffer_getRemainCnt(&rb2);
		retn = ringBuffer_pop(&rb2, &ch);
		printf("[%d] rb2_out_data=(%d),remain=%d,ret=%d.\n", i, ch, remain, retn);
	}	
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值