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

1. 序言
环形缓冲区(ring buffer),环形队列(ring queue) 多用于2个线程之间传递数据,是标准的先入先出(FIFO)模型。一般来说,对于多线程共享数据,需要使用mutex来同步,这样共享数据才不至于发生不可预测的修改/读取,然而,mutex的使用也带来了额外的系统开销,ring buffer/queue 的引入,就是为了有效地解决这个问题,因其特殊的结构及算法,可以用于2个线程中共享数据的同步,而且必须遵循1个线程push in,另一线程pull out的原则。

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

2. ring buffer 数据结构
struct _RingB
{
	SI32 r_cursor;
	SI32 w_cursor;
	SI32 tr_cursor;
	SI32 tw_cursor;
	SI32 length;
	char data[0];
};
ring buffer主要用于存储一段连续的数据块,例如网络接收的数据。
r_cursor 读指针,只在线程B中才能被修改,对于线程A,它是readonly的
tr_cursor 辅助读指针,只在线程B中才能被引用,用于计算当前有多少可读数据
w_cursor 写指针,只在线程A中才能被修改,对于线程B,它是readonly的
tw_cursor 辅助写指针,只在线程A中才能被引用,用于计算当前有多少空闲位置可以写入数据
length 缓冲区长度
data 缓冲区实体
需要注意的是,在data中,需要保留1byte的位置,因为:
a. push数据时,理论上来说,我们应该是从 thiz->tw_cursor = (thiz->w_cursor + 1) % thiz->length; 
开始写的,如果此时 thiz->tw_cursor == thiz->r_cursor, 我们认为此时缓冲区已满
b.  pull数据时,也是相同的道理,thiz->r_cursor == thiz->w_cursor,我们认为此时缓冲区无数据可读
也就是说,r_cursor == w_cursor 是一个特殊的位置,所以我们需要在data里面保留1byte。
具体原理可参考 IDirectSoundBuffer8 

函数列表:
RingB*	ringb_create(UI32 size);
void	ringb_destroy(RingB* thiz);
SI32	ringb_write_lock(RingB* thiz, SI8** ptr1, SI32* size1, SI8** ptr2, SI32* size2);
SI32	ringb_write_unlock(RingB* thiz, const SI8* ptr1, SI32 size1, const SI8* ptr2, SI32 size2);
SI32	ringb_write(SI8* ptr1, SI32* size1, SI8* ptr2, SI32* size2, const SI8* src, SI32 len);
SI32	ringb_read_lock(RingB* thiz, SI8** ptr1, SI32* size1, SI8** ptr2, SI32* size2);
SI32	ringb_read_unlock(RingB* thiz, const SI8* ptr1, SI32 size1, const SI8* ptr2, SI32 size2);
SI32	ringb_read(const SI8* ptr1, SI32* size1,const SI8* ptr2, SI32* size2, SI8* dst, SI32 len);

2. ring queue 数据结构
struct _RingQ
{
	SI32 r_cursor;
	SI32 w_cursor;
	SI32 length;
	void* data[0];
};
ring buffer主要用于存储指针,这个指针指向共享数据的entry.
r_cursor 读指针,只在线程B中才能被修改,对于线程A,它是readonly的
w_cursor 写指针,只在线程A中才能被修改,对于线程B,它是readonly的
length 缓冲区长度
data 缓冲区实体
与ring buffer,在data中,同样需要保留1byte的位置,原理与ring buffer相似,只是tw_cursor,tw_cursor
用临时变量代替而已。

函数列表:
RingQ*	ringq_create(SI32 size);
void	ringq_destroy(RingQ* thiz);
SI32	ringq_push(RingQ* thiz, void* data);
SI32	ringq_pop(RingQ* thiz, void** data);
SI32	ringq_fakePop(RingQ* thiz, void** data);
SI32	ringq_tryPush(RingQ* thiz);
SI32	ringq_tryPop(RingQ* thiz);
  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值