zoukankan      html  css  js  c++  java
  • 多读者多写者的无锁队列

    单读者单写者很容易进行冲突避免,毕竟他们操作的是不同的指针(head和rear),而多读者则需要共同操作head,多写者共同操作rear,似乎必须要加锁,锁机制是内核提供的一种对象,比较影响效率。
    可以借鉴spinlock的实现机制,利用CPU提供的原子指令(x86上有cmpxchg,即比较交换,当某个内存地址里的值等于某个值时,则将该地址里的内容与某个寄存器交换,这一系列操作是原子的,由CPU保证),实现CAS原子操作,意为Compare & Set(Swap?)。
     
    一种典型的CAS描述如下:
    bool compare_and_set(int *reg, int oldval, int newval){
    
    if(*reg==oldval){
    
    *reg=newval;
    
    return true;
    
    }
    
    return false;
    
    }

    记住这个CAS操作是原子的,即不可能多个线程通过CAS操作相同的对象。

     
    于是,对于入队列可以实现为
    void Enqueue(x){
    
    q=new node();
    
    q->value=x;
    
    q->next=NULL;
    
    do{
    
    p=tail;
    
    }while(!CAS(p->next,NULL,q));
    
    CAS(tail,p,q);
    
    }

    这种实现有个问题,即只有第一个线程执行了CAS(tail,p,q),其他的线程才能结束循环,继续下一步,而如果第一个线程异常终止或暂停(而没有成功执行CAS操作),则其他所有线程都要死循环。

    解决办法是,在do循环中,让线程自己遍历到真正的尾指针,而不是等待tail被更新。
    void Enqueue(x){
    
    q=new node();
    
    q->value=x;
    
    q->next=NULL;
    
    p=tail;
    
    do{
    
    while(p->next!=NULL) p=p->next;
    
    }while(!CAS(p->next,NULL,q));
    
    CAS(tail,p,q);
    
    }

    如此,即使第一个线程没有执行CAS(tail,p,q),其他线程也可以正常退出循环。

    然而,问题又来了,如果多个线程同时到达CAS(tail,p,q),那么只有第一个线程才能正确执行,因为其他的线程此时不满足tail==p,只有等到第一个线程正确执行CAS(tail,p,q)后,才能满足tail==p。遗憾的是,多个线程执行CAS(tail,p,q)的顺序是随机的,如果它们正好按照1,2,3,...的顺序执行,则最终tail可以指向正确的尾指针,如果是...,3,2,1,则前面所有线程的CAS(tail,p,q)都会失败,最后tail指向错误的结尾。
    为了在这个地方确定一个顺序,可以给每个线程的q一个编号,该编号即为该节点在链表里的序号,最后CAS(tail,p,q)前,判断当前q的序号是否大于tail的,如果大于,则执行,否则不执行。
    void Enqueue(x){
    
    q=new node();
    
    q->value=x;
    
    q->next=NULL;
    
    p=tail;
    
    q->id=p->id+1;
    
    do{
    
    while(p->next!=NULL) {p=p->next;q->id++;}
    
    }while(!CAS(p->next,NULL,q));
    
    do{
    
    p=tail;
    
    }while(q->id>p->id && CAS(tail,p,q));
    
    }
  • 相关阅读:
    数据库复习笔记
    mysql基础实验过程+遇到的问题的解决方法(error105处理)
    R文件变红原因to按钮变色的优化
    windos命令行设置网络
    牛客网-21天刷题计划-第2节 进阶-对称的二叉树
    0型文法、1型文法、2型文法、3型文法对照
    ES练习遇到错误
    安装kafka
    使用ES时踩过的坑
    前端报错
  • 原文地址:https://www.cnblogs.com/zszmhd/p/2973596.html
Copyright © 2011-2022 走看看