1、什么是CAS原子操作
在研究无锁之前。我们须要首先了解一下CAS原子操作——Compare & Set,或是 Compare & Swap,如今差点儿所有的CPU指令都支持CAS的原子操作,X86下相应的是 CMPXCHG 汇编指令。
2、操作系统里面关于“原子操作”的概念,一个操作是原子的(atomic),假设这个操作所处的层(layer)的更高层不能发现其内部实现与结构。原子操作能够是一个步骤,也能够是多个操作步骤。可是其顺序是不能够被打乱,或者分割掉仅仅运行部分。有了这个原子操作这个保证我们就能够实现无锁了。
3、CAS原子操作在维基百科中的代码描写叙述例如以下:
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;
}
也就是检查内存*reg里的值是不是oldval,假设是的话。则对其赋值newval。上面的代码总是返回old_reg_value,调用者假设须要知道是否更新成功还须要做进一步推断,为了方便,它能够变种为直接返回是否更新成功,例如以下:
bool compare_and_swap (int *accum, int *dest, int newval)
{
if ( *accum == *dest ) {
*dest = newval;
return true;
}
return false;
}
4、CAS 在各个平台下的实现
4.1 Linux GCC 支持的 CAS
GCC4.1+版本号中支持CAS的原子操作(完整的原子操作可參看 GCC Atomic Builtins)
1》: bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
2》: type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
4.2 Windows支持的CAS
在Windows下。你能够使用以下的Windows API来完毕CAS:(完整的Windows原子操作可參看MSDN的InterLocked Functions)
1: InterlockedCompareExchange ( __inout LONG volatile *Target, __in LONG Exchange, __in LONG Comperand);
4.3 C++ 11支持的CAS
C++11中的STL中的atomic类的函数能够让你跨平台。(完整的C++11的原子操作可參看 Atomic Operation Library)
template< class T >
bool atomic_compare_exchange_weak( std::atomic<T>* obj,
T* expected, T desired );
template< class T >
bool atomic_compare_exchange_weak( volatile std::atomic<T>* obj,
T* expected, T desired );
5、Fetch And Add
6、gcc从4.1.2提供了__sync_*系列的built-in函数,用于提供加减和逻辑运算的原子操作。
其声明如下:
type __sync_fetch_and_add (type *ptr, type value, ...)
type __sync_fetch_and_sub (type *ptr, type value, ...)
type __sync_fetch_and_or (type *ptr, type value, ...)
type __sync_fetch_and_and (type *ptr, type value, ...)
type __sync_fetch_and_xor (type *ptr, type value, ...)
type __sync_fetch_and_nand (type *ptr, type value, ...)
type __sync_add_and_fetch (type *ptr, type value, ...)
type __sync_sub_and_fetch (type *ptr, type value, ...)
type __sync_or_and_fetch (type *ptr, type value, ...)
type __sync_and_and_fetch (type *ptr, type value, ...)
type __sync_xor_and_fetch (type *ptr, type value, ...)
type __sync_nand_and_fetch (type *ptr, type value, ...)
这两组函数的区别在于第一组返回更新前的值,第二组返回更新后的值。
bool __sync_bool_compare_and_swap (type *ptr, type oldval type newval, ...)
type __sync_val_compare_and_swap (type *ptr, type oldval type newval, ...)
这两个函数提供原子的比较和交换,如果*ptr == oldval,就将newval写入*ptr,
第一个函数在相等并写入的情况下返回true.
第二个函数在返回操作之前的值。
7、CAS无锁操作可能产生的问题
7.1、CAS原语有三个参数,内存地址,期望值,新值。如果内存地址的值==期望值,表示该值未修改,此时可以修改成新值。否则表示修改失败,返回false,由用户决定后续操作
7.2、缺点:
使用CAS会造成ABA问题
ABA 问题
thread1意图对val=1进行操作变成2,cas(*val,1,2)。
thread1先读取val=1;thread1被抢占,让thread2运行。
thread2 修改val=3,又修改回1。
thread1继续执行,发现期望值与“原值”(其实被修改过了)相同,完成CAS操作。
解决方案
ABAʹ:添加额外的标记用来指示是否被修改。