多线程及多进程编程同步时可能出现的问题,如果一个值被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

ABA problem的更多相关文章

  1. SpinLock 自旋锁, CAS操作(Compare & Set) ABA Problem

    SpinLock 自旋锁 spinlock 用于CPU同步, 它的实现是基于CPU锁定数据总线的指令. 当某个CPU锁住数据总线后, 它读一个内存单元(spinlock_t)来判断这个spinlock ...

  2. 装逼名词-ABA CAS SpinLock

    今天看wiki,看到一个提到什么什么会陷入 race condition & ABA problem.丫的我没听过ABA呀,那么我去搜了一下,如下: http://www.bubuko.com ...

  3. 无锁队列以及ABA问题

    队列是我们非常常用的数据结构,用来提供数据的写入和读取功能,而且通常在不同线程之间作为数据通信的桥梁.不过在将无锁队列的算法之前,需要先了解一下CAS(compare and swap)的原理.由于多 ...

  4. JAVA与ABA问题

    在<JAVA并发编程实战>的第15.4.4节中看到了一些关于ABA问题的描述.有一篇文章摘录了书里的内容. 书中有一段内容为: 如果在算法中采用自己的方式来管理节点对象的内存,那么可能出现 ...

  5. 【Java并发编程】2、无锁编程:lock-free原理;CAS;ABA问题

    转自:http://blog.csdn.net/kangroger/article/details/47867269 定义 无锁编程是指在不使用锁的情况下,在多线程环境下实现多变量的同步.即在没有线程 ...

  6. Lock-Free 编程

    文章索引 Lock-Free 编程是什么? Lock-Free 编程技术 读改写原子操作(Atomic Read-Modify-Write Operations) Compare-And-Swap 循 ...

  7. boost 无锁队列

    一哥们翻译的boost的无锁队列的官方文档 原文地址:http://blog.csdn.net/great3779/article/details/8765103 Boost_1_53_0终于迎来了久 ...

  8. 锁开销优化以及 CAS 简单说明

    锁开销优化以及 CAS 简单说明 锁 互斥锁是用来保护一个临界区,即保护一个访问共用资源的程序片段,而这些共用资源又无法同时被多个线程访问的特性.当有线程进入临界区段时,其他线程或是进程必须等待. 在 ...

  9. Game Engine Architecture 4

    [Game Engine Architecture 4] 1.a model of multiple semi-independent flows of control simply matches ...

随机推荐

  1. unison + inotify 实现文件实时双向同步部署步骤

    unison + inotify 实现文件实时双向同步部署步骤 一. Unison简介 Unison是Windows.Linux以及其他Unix平台下都可以使用的文件同步工具,它能使两个文件夹(本地或 ...

  2. shiro实现APP、web统一登录认证和权限管理

    先说下背景,项目包含一个管理系统(web)和门户网站(web),还有一个手机APP(包括Android和IOS),三个系统共用一个后端,在后端使用shiro进行登录认证和权限控制.好的,那么问题来了w ...

  3. [反汇编练习] 160个CrackMe之018

    [反汇编练习] 160个CrackMe之018. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  4. cocos2d-x中的Jni使用(C++与Andriod方法互调)

    作者:何卫 转载请注明,原文链接:http://www.cnblogs.com/hewei2012/p/3376616.html 前提条件: 1.操作的游戏工程和cocos2d_x游戏引擎是一个目录的 ...

  5. AJAX在GBK编码页面中传中文参数乱码的问题

    ---恢复内容开始--- 页面编码是GBK的情况下传递中文有乱码,解决方法如下: 在ajax传递前用若是Array,JSON,等其它对象,可用JSON.stringfy字符串序列化后,赋值给ajax传 ...

  6. MYSQL的分区字段,必须包含在主键字段内

    MYSQL的分区字段,必须包含在主键字段内   MYSQL的分区字段,必须包含在主键字段内 在对表进行分区时,如果分区字段没有包含在主键字段内,如表A的主键为ID,分区字段为createtime ,按 ...

  7. 【DFS深搜初步】HDOJ-2952 Counting Sheep、NYOJ-27 水池数目

    [题目链接:HDOJ-2952] Counting Sheep Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 ...

  8. css清除浮动的两种方式(clearfix和clear)

    最近总是在用浮动,这两种方式总是浮现在眼前,或者说去掉父级和同级浮动样式总在思考中.两种方式怎么写都在base.css中. 在做瑞祥之旅的过程中,还是吃了一个大亏,就是清除浮动,不管是同级还是父级,都 ...

  9. Linux 系统编程

    简介和主要概念 Linux 系统编程最突出的特点是要求系统程序员对它们工作的的系统的硬件和操作系统有深入和全面的了解,当然它们还有库和系统调用上的区别. 系统编程分为:驱动编程.用户空间编程和网络编程 ...

  10. 【LeetCode 209】Minimum Size Subarray Sum

    Given an array of n positive integers and a positive integer s, find the minimal length of a subarra ...