一个无锁线程安全的队列,
参考项目
1.queue
2.ringbuffer
3.goqueue
构建一个对象,包含容量,基本数据结构,读写位置; 容量使用 2的幂次的长度 为了方便位置定位的优化 使用切片作为基本数据结构,读写分离,分别记录需要读写的位置(对应切片的下标); 实际队列中的数据每一个冗余一个和外部切片下标幂次对应的位置(卡槽更好理解),约束读取的动作(是否可读写,或是否是本轮操作)
1.是否可读写,判断读写的下标,重合时代表队列为空,其他位置都是有数据,前后只不过是数据位置不同, 这里注意的是,先去获取可操作的状态,然后再去读写数据,如果在并发操作中,可能会遇到获取到操作权限还没来的及操作的情况,MaxWait 这个变量使用的部分描述就是
答:因为用来代替取余操作,提高效率 解释:二的幂次的值减1之后,所有位都是1(比如 8-1 的二进制就是 111),然后 & 上需要取余的值,转化到十进制就是对应位置 例子:长度是 8,输入一个 14
// 8-1 对应二进制 111
// 14 对应二进制 1110
对他们进行 & 位操作
111
1110
得:110 对应十进制 6
该操作与 14%8=1余6 的取余操作结果一致
答:为了和外部(读写的索引)的位置对应,标志该位置是否可读(可写),并且约束读写的动作。
因为是无锁操作,先预定操作(获得可操作状态),再去实际读(写)数据。
EXAMPLE 使用列子更直白 , 一个容量(cap)为 8 的队列中
外部读写指针
putPos :0
getPos :0
内部数据队列第一个元素的
putID:0
getID:0
当加入一个元素
外部读写指针
putPos :1
getPos :0
内部数据队列第一个元素的
putID:9 // 标志着下一轮的位置,因为下一次到这个位置肯定是对应外部 putPos:9(因为容量为 8 )
getID:0
以此类推