CAS与无锁队列

                                    CAS与无锁队列

1.无锁同步CAS
当我们如果只是由于一条代码出现了线程安全问题,比如说多个线程都要往一个队列中的尾部插入一个
元素,那么我们的tail->next=newnode;使我们一条必要的代码。但是当我们拿到tail的时候,在执行
这条指令前,其他线程率先在原来的队列尾部插入元素,这就会引起tail的失效,因为tail的值变了。
这种情况下如果我们加入了锁只是为了控制一条临界代码,那么开销就太大了。因此我们就引入了我们
cpu的CAS操作。
bool compare_and_swap (int *accum, int *dest, int newval)
{
  if ( *accum == *dest ) {
      *accum = newval;
      return true;
  }
  return false;
}CAS(1)
int compare_and_swap (int* reg, int oldval, int newval)
{
  int old_reg_val = *reg;
  if (old_reg_val == oldval)
     *reg = newval;
  return old_reg_val;
}CAS(2)
以上两个函数就是CAS的大体步骤,其实就是一个安全检查。


2. 我们将CAS用在队列当中构造一个无锁队列来说明以上CAS的具体用途
***
EnQueue(x) //进队列Q
{
    //准备新加入的结点数据
    q = new record();
    q->value = x;
    q->next = NULL;
 
    do {
        p = tail; //取链表尾指针的快照
    } while( !CAS(p->next, NULL, q)); //如果没有把结点链在尾指针上,再试
 
    CAS(tail, p, q); //置尾结点
}
这个while在每个对这个队列尾插的线程都要写,如上CAS(1)函数,当结果为真才能跳出循环,而
结果为真就意味*accum == *dest这代表这个p的next里面放的是NULL也就是没有往尾部插元素,接下
来如上CAS(1)出了while循环并且,p的next里面替换成了q(新节点)。这个时候其他的线程再也
进不来了,因为这个线程率先改变NULL为q,其他线程一直死循环。这时候如上的CAS(tail, p, q);
可以安全经行没有其他线程打扰。这个CAS(2)就是带入原来的tail如果和p相同就更新tail(这里
其实是想检测我们是否插入了新节点更不更新tail,如果我们tail—>next!=NULL,插入了,我们要用
这个线程跟新tail,好让其他线程可以走出死循环)
注:我们理解这里tail是公用的,而其他的量都在栈上是线程私有的。
***
DeQueue() //出队列
{
    do{
        p = head;
        if (p->next == NULL){
            return ERR_EMPTY_QUEUE;
        }
    while( !CAS(head, p, p->next));
    return p->next->value;
}

猜你喜欢

转载自blog.csdn.net/qq_41784469/article/details/80930565