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