ABA问题

ABA问题分析

  /* Naive lock-free stack which suffers from ABA problem.*/
  class Stack {
    std::atomic<Obj*> top_ptr;
    //
    // Pops the top object and returns a pointer to it.
    //
    Obj* Pop() {
      while(1) {
        Obj* ret_ptr = top_ptr;
        if (!ret_ptr) return nullptr;
        // For simplicity, suppose that we can ensure that this dereference is safe
        // (i.e., that no other thread has popped the stack in the meantime).
        Obj* next_ptr = ret_ptr->next;
        // If the top node is still ret, then assume no one has changed the stack.
        // (That statement is not always true because of the ABA problem)
        // Atomically replace top with next.
        if (top_ptr.compare_exchange_weak(ret_ptr, next_ptr)) {
          return ret_ptr;
        }
        // The stack has changed, start over.
      }
    }
    //
    // Pushes the object specified by obj_ptr to stack.
    //
    void Push(Obj* obj_ptr) {
      while(1) {
        Obj* next_ptr = top_ptr;
        obj_ptr->next = next_ptr;
        // If the top node is still next, then assume no one has changed the stack.
        // (That statement is not always true because of the ABA problem)
        // Atomically replace top with obj.
        if (top_ptr.compare_exchange_weak(next_ptr, obj_ptr)) {
          return;
        }
        // The stack has changed, start over.
      }
    }
  };

举个例子:当前全局变量s ,s的数据是 top->A->B->C

  { // Thread 2 runs pop:
    ret = A;
    next = B;
    compare_exchange_weak(A, B)  // Success, top = B
    return A;
  } // Now the stack is top → B → C
  { // Thread 2 runs pop again:
    ret = B;
    next = C;
    compare_exchange_weak(B, C)  // Success, top = C
    return B;
  } // Now the stack is top → C
  delete B;
  { // Thread 2 now pushes A back onto the stack:
    A->next = C;
    compare_exchange_weak(C, A)  // Success, top = A
  }


由例子可以看出 假色全局变量 stack s;加入当前存在两个线程对这个全局变量s进行操作,线程1 调用了pop 当执行到

 Obj* next_ptr = ret_ptr->next;

的时候线程1 被挂起,此时线程2进行pop操作 结果变为 top->B->C 然而2继续pop  则s变为 top->C 此时线程2进行push A操作则 堆栈变为top->A->C. 线程2执行完, 线程1被唤醒,那么线程1进行

top_ptr.compare_exchange_weak(ret_ptr, next_ptr)

操作 发现 ret_ptr的确就是 A,替换成 nest_ptr(即B) 但是当前B已经被销毁了,所以程序是崩毁的。


有人使用过的一种解决办法就是修改地址法:目的就是为了使

top_ptr.compare_exchange_weak(next_ptr, obj_ptr)
这个操作失败,那么怎么样才可以使这个操作失败呢?因为 他成功的前提是 top_ptr 与 next_ptr相等,所以只要使next_ptr发生变化就可以了,因为当非本线程对 next_ptr做过手脚的话 就应该留下一点痕迹 这样就可以解决该问题了。

通过考察各种基于CAS原子操作的无锁数据结构实现,目前公认可实现无锁安全的数据结构是数组和单向队列。其他实现都一定程度上受到复杂度和ABA问题的威胁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值