为什么需要⽆锁队列
锁引起的问题:
Cache损坏(Cache trashing)
在同步机制上的争抢队列
动态内存分配
无锁队列的实现
一读一写无锁队列实现(参考zmq的无锁队列实现)
![](https://img-blog.csdnimg.cn/edc3d86127e64dce870e977e0ff42e01.png)
yqueue_t内部有三个chunk_t类型指针以及对应的索引位置:
begin_chunk/begin_pos:
begin_chunk 用于指向队列头的chunk,begin_pos 用于指向队列第一个
元素在当前chunk中的位置。
back_chunk/back_pos:
back_chunk 用于指向队列尾的chunk,back_pos 用于指向队列最后一个元素在当前chunk的位置。
end_chunk/end_pos:
由于chunk是批量分配的,所以end_chunk⽤于指向分配的最后一个chunk位置。
pipe_t是对queue_t的读写封装,
主要有几个要注意的:基本的代码阅读应该好理解,就是有一个函数比较难理解
ypipe_t 的实现:
写入的过程
取出队列的尾部,然后调用push,这里很简单,如果是完成则要刷新f指针
刷新数据,只有刷新了数据,读线程才能读取得到。
如果w=f: 说明没有push数据,因为push完成f指针会移动
否则:尝试将c=f指针,
如果c不等于w,说明c原来的值为null,说明读线程挂起,这时候要可以直接更新c=f,w=f,返回false让写线程通知读线程可读
否则:直接更新w=f,return true;
读取的过程
如果指针r指向的是队头元素(r==&queue.front())或者r没有指向任何元素(NULL)则说明队列中并没有可读的数据,下一步
进入尝试去预取数据。预取就是令 r=c,⽽c在write中被指向f,这时从queue.front()到f这个位置的数据将被预取出来。
如果已经预取,每次调⽤read都能取出⼀个数据,这时不会触发原子锁操作。
当预取不到数据,线程睡眠,等待写线程写入发送信号来触发读操作。
测试代码:
测试代码实现:
单独线程压入队列
单线程读取:
具体实现源码后续会更新到gitee