原子 CAS 与 锁

原子操作


何为原子操作?

原子操作是指不会被其他例程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另一个例程)。

如何实现原子操作

从原子操作的概念来看, 只要确保操作期间不会被打断都可以视为原子性。 所以不仅基本类型,那些mutex, spin_lock 保护的操作也是原子操作。

gcc 提供了一系列基本类型的 atomic memory access. C++/Java 都提供了atomic的Library.

但是理解atomic需要深入到assembly层面, 以linux kernel 为例,int对应的原子类型是volatile的封装。

volatile 起到内存屏障的作用, 能够将CPU cache实时更新,确保所有CPU cache 都是最新值. 这一机制是CPU的缓存一致协议自动完成的。(CPU缓存一致协议MESI)

在单核OS时代,实现原子操作很简单,只需要关中断阻止进程调度即可。 SMP-OS中,就需要使用CPU的原语”LOCK”,阻止多例程访问地址。

/*Linux Kernel atomic operations
* From: linux-2.6.0/linux-2.6.0/include/asm-x86_64/atomic.h
*/

typedef struct { volatile int counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

/**
 * atomic_read - read atomic variable
 * @v: pointer of type atomic_t
 *
 * Atomically reads the value of @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_read(v)		((v)->counter)

/**
 * atomic_set - set atomic variable
 * @v: pointer of type atomic_t
 * @i: required value
 *
 * Atomically sets the value of @v to @i.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
#define atomic_set(v,i)		(((v)->counter) = (i))

/**
 * atomic_add - add integer to atomic variable
 * @i: integer value to add
 * @v: pointer of type atomic_t
 *
 * Atomically adds @i to @v.  Note that the guaranteed useful range
 * of an atomic_t is only 24 bits.
 */
static __inline__ void atomic_add(int i, atomic_t *v)
{
	__asm__ __volatile__(
		LOCK "addl %1,%0"
		:"=m" (v->counter)
		:"ir" (i), "m" (v->counter));
}

/**
 * atomic_sub - subtract the atomic variable
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 *
 * Atomically subtracts @i from @v.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
static __inline__ void atomic_sub(int i, atomic_t *v)
{
	__asm__ __volatile__(
		LOCK "subl %1,%0"
		:"=m" (v->counter)
		:"ir" (i), "m" (v->counter));
}

/**
 * atomic_sub_and_test - subtract value from variable and test result
 * @i: integer value to subtract
 * @v: pointer of type atomic_t
 *
 * Atomically subtracts @i from @v and returns
 * true if the result is zero, or false for all
 * other cases.  Note that the guaranteed
 * useful range of an atomic_t is only 24 bits.
 */
static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
{
	unsigned char c;

	__asm__ __volatile__(
		LOCK "subl %2,%0; sete %1"
		:"=m" (v->counter), "=qm" (c)
		:"ir" (i), "m" (v->counter) : "memory");
	return c;

Table of Contents