无锁编程关键点

331 篇文章 0 订阅

无锁编程关键点.看了下,作个笔记.
无锁数据依靠的是CAS.即比较置比较交换.
参考1
参考2
比较交换的实现:

int compare_and_swap (int* reg, int oldval, int newval) 
{
  ATOMIC();
  int old_reg_val = *reg;
  if (old_reg_val == oldval) 
     *reg = newval;
  END_ATOMIC();
  return old_reg_val;
}

看见没有,原子操作,要先有个旧对象,然后相互比较,即看看数据变没有,数据没变即进行新值替换
这里比平常多一步判定原先数据变化的操作.
因此,这也是碰运气.如果数据,比如指针,看起来没变化,但实质上,指针的内容已经变化(释放并重用)了,这就是漏洞的根源了.所以,无锁编程,就是要解决这个问题,即如何判定这一段时间,数据是否发生了变化.
接下来几个比较交换弱,比较交换强,找cpp参考的原子操作.
伪码:

if *this == expected:
    *this = desired;
else:
   expected = *this;

仔细观察如下代码:

if ( head == new_node->new){//数据没变
     head = new_node;//直接压入数据
     return true;//成功.
}else{//数据变化 
    new_node->next = head;//头已变化,得跟着变化
    return false;//此次失败,下次再来
}//这是压,弹没写清楚.
//下面还有.

现在几乎所有的CPU指令都支持CAS的原子操作,X86下对应的是 CMPXCHG 汇编指令。
无锁队列的链表实现:

EnQueue(x) //进队列
{
    //准备新加入的结点数据
    q = new record();
    q->value = x;
    q->next = NULL;
   do {
        p = tail; //取链表尾指针的快照
    } while( CAS(p->next, NULL, q) != TRUE); //如果没有把结点链在尾指针上,再试
 //原子比较,这一步比较若为相同,即未被处理,
    CAS(tail, p, q); //置尾结点
    //原子加.是两个相邻原子操作.
}

无锁编程,其实就是看待添加位置是否被占.已占,重新调整待添加位置.然后多个线程不断循环操作.只要判断位置是否被占与添加尾结点,这两步是原子操作.不然,就是一片混乱了.所以,所谓的无锁编程就是抢占法.只在不得不排外的情况下,进行原子操作.
改良版,万一当前线程坏了,我觉得太多此一举了.没必要,或者只2次,也麻烦.也搞不懂.见参考2.
好,下面是出列:

DeQueue() //出队列
{
    do{
        p = head;
        if (p->next == NULL){
            return ERR_EMPTY_QUEUE;
        }
    }while( CAS(head, p, p->next) != TRUE );//陈大神这里少个}.一样的,比较时变化了.在这一步里面进行操作.如果为真,代表操作成功,即弹出去了.否则,移动当前指针.
    return p->next->value;//返回数据
}

所谓的ABA就是我上面说的,你看起来没变的东西,实质上已经变了.就像指针,主要还是那个问题:如何判定是否已被占?
无锁编程,总之,就是一个抢占问题.将锁的粒度控制在最小.无关的排外都去掉了.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值