Skip to content

shitingbao/quequ

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

quequ

一个无锁线程安全的队列, 参考项目
1.queue
2.ringbuffer 3.goqueue

基本思路

构建思路

构建一个对象,包含容量,基本数据结构,读写位置; 容量使用 2的幂次的长度 为了方便位置定位的优化 使用切片作为基本数据结构,读写分离,分别记录需要读写的位置(对应切片的下标); 实际队列中的数据每一个冗余一个和外部切片下标幂次对应的位置(卡槽更好理解),约束读取的动作(是否可读写,或是否是本轮操作)

逻辑思路

1.是否可读写,判断读写的下标,重合时代表队列为空,其他位置都是有数据,前后只不过是数据位置不同, 这里注意的是,先去获取可操作的状态,然后再去读写数据,如果在并发操作中,可能会遇到获取到操作权限还没来的及操作的情况,MaxWait 这个变量使用的部分描述就是

为什么选择2的幂次的长度

答:因为用来代替取余操作,提高效率 解释:二的幂次的值减1之后,所有位都是1(比如 8-1 的二进制就是 111),然后 & 上需要取余的值,转化到十进制就是对应位置 例子:长度是 8,输入一个 14

// 8-1 对应二进制 111
// 14 对应二进制 1110
对他们进行 & 位操作
    111
   1110
 110 对应十进制 6
 该操作与 14%8=1余6 的取余操作结果一致

为什么除了读写的位置,数据队列中每个元素都有保存对应位置(卡槽)

答:为了和外部(读写的索引)的位置对应,标志该位置是否可读(可写),并且约束读写的动作。
因为是无锁操作,先预定操作(获得可操作状态),再去实际读(写)数据。

EXAMPLE 使用列子更直白 , 一个容量(cap)为 8 的队列中

外部读写指针
putPos0
getPos0
内部数据队列第一个元素的
putID0  
getID0

当加入一个元素

外部读写指针
putPos1
getPos0
内部数据队列第一个元素的
putID9 // 标志着下一轮的位置,因为下一次到这个位置肯定是对应外部  putPos:9(因为容量为 8 )
getID0

以此类推

About

a no lock queue

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages