码迷,mamicode.com
首页 > 其他好文 > 详细

无锁队列

时间:2018-03-18 01:23:43      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:pos   pop   unlock   while   val   多线程   变量   blog   tar   

1 伪命题

这本身是个伪命题。

多线程之间使用队列是一定需要做到同步的。也就是说一定是需要同步手段的,一定要在一个线程读写的时候,阻塞另一个线程。既然不然用锁,那就是用原子变量吧。

 

2 CAS

3 实现

队列,这里使用链表来实现

struct ListNode
{
 ListNode *next;
 int val;     
 ListNode(int x):val(x),ListNode(nullptr){}
};

class UnlockQueue
{
public:
   void push(int x);
   int pop(); 
private:
  ListNode *push_start;//
  ListNode *pop_start;
};

  

然后,考虑push,在push的时候,要在push_start的next上加节点,此时push_start->next是等于nullptr的。

void UnlockQueue::push(int x)
{
 ListNode *n=new ListNode(x);
 ListNode *tmp=push_start;
  
 while(cas(push_start->next,nullptr,n)!=true)
 {
   tmp=push_start;
 }
  push_start=n;
}

  

解释一下,创建要添加的节点以后,就用cas轮序push_start->next,当等于nullptr的时候,就将next设置为n。

因为是个原子操作,因此同一时刻,就只有这个线程在设置next。同时,当别的线程设置了next以后,那么next就不在指向nullptr,那么就会一直循环。

当设置完以后,就将push_start设置为n,此时其他线程,tmp指向改变,真正的指向尾部,因此其他线程就可在cas通过了。

因此本质上还是锁。但是这里使用了轮询。

原因在于,这个设置过程时间很短暂,所以没有必要使用锁。

 

这里,类的两个字段,可以不用加上volatile关键字修饰,因为别的线程会改变自己正在使用的数据。因为在cas的实现上,这两个数据成员所处的内存一直是由某个cpu独享的。因此不会有其他核心去改变这个数据。

 

看到这里估计也就明白了,这其实是一个自己实现的自旋锁,嗯,自旋锁,使用轮询的方式,不让进程阻塞。

 

对应的pop操作,同理,也是这样的思想。

  

4 CAS原理

 

无锁队列

标签:pos   pop   unlock   while   val   多线程   变量   blog   tar   

原文地址:https://www.cnblogs.com/perfy576/p/8593899.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!