zoukankan      html  css  js  c++  java
  • ABA problem

    多线程及多进程编程同步时可能出现的问题,如果一个值被P1读取两次,两次的值相同,据此判断该值没有被修改过,但该值可能在两次读取之间被P2修改为另外一个value,并在P1再次读取之前修改回了原值。P1被愚弄,认为该值一直没有改变过。

    下面的事件序列会导致ABA问题

    1.线程P1访问共享内存的value A。

    2.P1被抢占,P2开始运行

    3.P2读取共享内存的value A,把它变成B,在被抢占之前再次变成A

    4. 线程P1再次执行,看到共享内存的A还是原值,继续执行

    P1虽然继续执行,但P2隐含的修改可能导致P1的执行结果是错误的。 

      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 std::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.
          }
        }
      };

    栈的初始化序列是A->B->C

    线程1开始执行POP

    ret=A

    next=B

    线程1在执行compare_exchange_weak前被挂起

    线程2开始执行

    { // 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
      }

    这是栈是A->C,B已经被delete了。

    线程2挂起,线程1继续执行。

    compare_exchange_weak(A, B)

    检查了A的值还是原值,执行动作,但B已经被释放了,就引发了未定义的行为,这种隐含的错误也非常难于调试。

    本文内容引自维基百科

    https://en.wikipedia.org/wiki/ABA_problem 

  • 相关阅读:
    【python刷题】前缀和
    【python刷题】数组链表去重
    【python刷题】滑动窗口法
    【python刷题】二分查找
    【python刷题】广度优先搜索(BFS)
    【python刷题】回溯算法(深度优先搜索DFS)
    机器学习十讲-第三讲分类
    数学知识-质数&约数
    树与图的DFS与BFS
    桥梁保护与监控-开发进度(二)
  • 原文地址:https://www.cnblogs.com/learn-my-life/p/5260047.html
Copyright © 2011-2022 走看看