C语言实现环形缓冲区

1、简述环形缓冲区可以把它的读出端(以下简称R)和写入端(以下简称W)想象成是两个人在体育场跑道上追逐(R追W)。当R追上W的时候,就是缓冲区为空;当W追上R的时候(W比R多跑一圈),就是缓冲区满。

为了形象起见,去找来一张图并略作修改,如下:




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

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

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



示例程序:

#ifndef KFIFO_HEADER_H	 
#define KFIFO_HEADER_H	

//判断x是否是2的次方  
#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))  
//取a和b中最小值  
#define min(a, b) (((a) < (b)) ? (a) : (b))  
  
struct ring_buffer	
{  
	void		 *buffer;	  //缓冲区	
	uint32_t	 size;		 //大小  
	uint32_t	 in;		 //入口位置  
	uint32_t	   out; 	   //出口位置  
	pthread_mutex_t *f_lock;	//互斥锁  
};	
  
//初始化缓冲区	
struct ring_buffer* ring_buffer_init(void *buffer, uint32_t size, pthread_mutex_t *f_lock)	
{  
	assert(buffer);  
	struct ring_buffer *ring_buf = NULL;  
	if (!is_power_of_2(size))  
	{  
		fprintf(stderr,"size must be power of 2.\n");  
		return ring_buf;  
	}  
	ring_buf = (struct ring_buffer *)malloc(sizeof(struct ring_buffer));  
	if (!ring_buf)	
	{  
		fprintf(stderr,"Failed to malloc memory,errno:%u,reason:%s",  
			errno, strerror(errno));  
		return ring_buf;  
	}  
	memset(ring_buf, 0, sizeof(struct ring_buffer));  
	ring_buf->buffer = buffer;	
	ring_buf->size = size;	
	ring_buf->in = 0;  
	ring_buf->out = 0;	
        ring_buf->f_lock = f_lock;	
	return ring_buf;  
}  
//释放缓冲区  
void ring_buffer_free(struct ring_buffer *ring_buf)  
{  
	if (ring_buf)  
	{  
	if (ring_buf->buffer)  
	{  
		free(ring_buf->buffer);  
		ring_buf->buffer = NULL;  
	}  
	free(ring_buf);  
	ring_buf = NULL;  
	}  
}  
  
//缓冲区的长度	
uint32_t __ring_buffer_len(const struct ring_buffer *ring_buf)	
{  
	return (ring_buf->in - ring_buf->out);	
}  
  
//从缓冲区中取数据	
uint32_t __ring_buffer_get(struct ring_buffer *ring_buf, void * buffer, uint32_t size)	
{  
	assert(ring_buf || buffer);  
	uint32_t len = 0;  
	size  = min(size, ring_buf->in - ring_buf->out);		  
	/* first get the data from fifo->out until the end of the buffer */  
	len = min(size, ring_buf->size - (ring_buf->out & (ring_buf->size - 1)));  
	memcpy(buffer, ring_buf->buffer + (ring_buf->out & (ring_buf->size - 1)), len);  
	/* then get the rest (if any) from the beginning of the buffer */  
	memcpy(buffer + len, ring_buf->buffer, size - len);  
	ring_buf->out += size;	
	return size;  
}  

//从缓冲区丢弃数据
uint32_t __ring_buffer_throw(struct ring_buffer *ring_buf, uint32_t size)	
{  
	assert(ring_buf);  
	uint32_t len = 0;  
	size  = min(size, ring_buf->in - ring_buf->out);		  
	ring_buf->out += size;	
	return size;  
}  



//向缓冲区中存放数据  
uint32_t __ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)  
{  
	assert(ring_buf || buffer);  
	uint32_t len = 0;  
	size = min(size, ring_buf->size - ring_buf->in + ring_buf->out);  
	/* first put the data starting from fifo->in to buffer end */  
	len  = min(size, ring_buf->size - (ring_buf->in & (ring_buf->size - 1)));  
	memcpy(ring_buf->buffer + (ring_buf->in & (ring_buf->size - 1)), buffer, len);	
	/* then put the rest (if any) at the beginning of the buffer */  
	memcpy(ring_buf->buffer, buffer + len, size - len);  
	ring_buf->in += size;  
	return size;  
}  
  
uint32_t ring_buffer_len(const struct ring_buffer *ring_buf)  
{  
	uint32_t len = 0;  
	pthread_mutex_lock(ring_buf->f_lock);  
	len = __ring_buffer_len(ring_buf);	
	pthread_mutex_unlock(ring_buf->f_lock);  
	return len;  
}  
  
uint32_t ring_buffer_get(struct ring_buffer *ring_buf, void *buffer, uint32_t size)  
{  
	uint32_t ret;  
	pthread_mutex_lock(ring_buf->f_lock);  
	ret = __ring_buffer_get(ring_buf, buffer, size);  
	//buffer中没有数据	
	if (ring_buf->in == ring_buf->out)	
	ring_buf->in = ring_buf->out = 0;  
	pthread_mutex_unlock(ring_buf->f_lock);  
	return ret;  
}  

uint32_t ring_buffer_throw(struct ring_buffer *ring_buf, uint32_t size)  
{  
	uint32_t ret;  
	pthread_mutex_lock(ring_buf->f_lock);  
	ret = __ring_buffer_throw(ring_buf, size);  
	//buffer中没有数据	
	if (ring_buf->in == ring_buf->out)	
	ring_buf->in = ring_buf->out = 0;  
	pthread_mutex_unlock(ring_buf->f_lock);  
	return ret;  
}  

  
uint32_t ring_buffer_put(struct ring_buffer *ring_buf, void *buffer, uint32_t size)  
{  
	uint32_t ret;  
	pthread_mutex_lock(ring_buf->f_lock);  
	ret = __ring_buffer_put(ring_buf, buffer, size);  
	pthread_mutex_unlock(ring_buf->f_lock);  
	return ret;  
}  
#endif	

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值