标题：原子操作
简介
在多进程（线程）访问资源时，能够确保所有其他的进程（线程）都不在同一时间内访问相同的资源。
原子操作：UP和SMP的异同
-----------------------------------------------------------
"原子操作（atomic operation）是不需要synchronized"，这是Java多线程编程的老生常谈了。所谓原子操作是指不会被线程调度机制打断的操作；这种操作一旦开始，就一直运行到结束，中间不会有任何 context switch （切换到另一个线程）。通常所说的原子操作包括对非long和double型的primitive进行赋值，以及返回这两者之外的primitive。之所以要把它们排除在外是因为它们都比较大，而JVM的设计规范又没有要求读操作和赋值操作必须是原子操作（JVM可以试着去这么作，但并不保证）。不过如果你在long或double前面加了volatile，那么它就肯定是原子操作了。
特性
原子操作是不可分割的，在执行完毕之前不会被任何其它任务或事件中断。在单处理器系统（UniProcessor）中，能够在单条指令中完成的操作都可以认为是" 原子操作"，因为中断只能发生于指令之间。这也是某些CPU指令系统中引入了test_and_set、test_and_clear等指令用于临界资源互斥的原因。但是，在对称多处理器（Symmetric Multi-Processor）结构中就不同了，由于系统中有多个处理器在独立地运行，即使能在单条指令中完成的操作也有可能受到干扰。我们以decl （递减指令）为例，这是一个典型的"读－改－写"过程，涉及两次内存访问。设想在不同CPU运行的两个进程都在递减某个计数值，可能发生的情况是：
⒈ CPU A(CPU A上所运行的进程，以下同）从内存单元把当前计数值⑵装载进它的寄存器中；
⒉ CPU B从内存单元把当前计数值⑵装载进它的寄存器中。
⒊ CPU A在它的寄存器中将计数值递减为1；
⒋ CPU B在它的寄存器中将计数值递减为1；
⒌ CPU A把修改后的计数值⑴写回内存单元。
⒍ CPU B把修改后的计数值⑴写回内存单元。
我们看到，内存里的计数值应该是0，然而它却是1。如果该计数值是一个共享资源的引用计数，每个进程都在递减后把该值与0进行比较，从而确定是否需要释放该共享资源。这时，两个进程都去掉了对该共享资源的引用，但没有一个进程能够释放它--两个进程都推断出：计数值是1，共享资源仍然在被使用。
硬件支持
原子性不可能由软件单独保证--必须需要硬件的支持，因此是和架构相关的。在x86 平台上，CPU提供了在指令执行期间对总线加锁的手段。CPU芯片上有一条引线#HLOCK pin，如果汇编语言的程序中在一条指令前面加上前缀"LOCK"，经过汇编以后的机器代码就使CPU在执行这条指令的时候把#HLOCK pin的电位拉低，持续到这条指令结束时放开，从而把总线锁住，这样同一总线上别的CPU就暂时不能通过总线访问内存了，保证了这条指令在多处理器环境中的原子性。
Linux内核中的原子操作
-----------------------------------------------------------
原子操作大部分使用汇编语言实现，因为c语言并不能实现这样的操作。
* 在x86的原子操作实现代码中，定义了LOCK宏，这个宏可以放在随后的内联汇编指令之前。如果是SMP，LOCK宏被扩展为lock指令；否则被定义为空 -- 单CPU无需防止其它CPU的干扰，锁内存总线完全是在浪费时间。
#ifdef CONFIG_SMP
#define LOCK "lock ; "
#else
#define LOCK ""
#endif
* typedef struct { volatile int counter; } atomic_t;
在所有支持的体系结构上原子类型atomic_t都保存一个int值。在x86的某些处理器上，由于工作方式的原因，原子类型能够保证的可用范围只有24位。volatile是一个类型描述符，要求编译器不要对其描述的对象作优化处理，对它的读写都需要从内存中访问。
* #define ATOMIC_INIT(i) { (i) }
用于在定义原子变量时，初始化为指定的值。如：
static atomic_t count = ATOMIC_INIT⑴；
* static __inline__ void atomic_add(int i,atomic_t *v)
----------------------------------------
将v指向的原子变量加上i。该函数不关心原子变量的新值，返回void类型。
格式
在下面的实现中，使用了带有C/C++表达式的内联汇编代码，格式如下（参考《AT&T ASM Syntax》）：
__asm__ __volatile__("Instruction List" : Output : Input : Clobber/Modify);
__asm__ __volatile__指示编译器原封不动保留表达式中的汇编指令系列，不要考虑优化处理。涉及的约束还包括：
⒈ 等号约束（=）：只能用于输出操作表达式约束，说明括号内的左值表达式v->counter是write-only的。
⒉ 内存约束（m）：表示使用不需要借助寄存器，直接使用内存方式进行输入或输出。
⒊ 立即数约束（i）：表示输入表达式是一个立即数（整数），不需要借助任何寄存器。
⒋ 寄存器约束（r）：表示使用一个通用寄存器，由GCC在%eax/%ax/%al、%ebx/%bx/%bl、%ecx/%cx/%cl和%edx/%dx/%dl中选取一个合适的。
相关程序
{
__asm__ __volatile__(
LOCK "addl %1,%0"
："=m" (v->counter)
："ir" (i),"m" (v->counter));
}
* static __inline__ int atomic_sub_and_test(int i,atomic_t *v)
----------------------------------------
从v 指向的原子变量减去i，并测试是否为0。若为0，返回真，否则返回假。由于x86的subl指令会在结果为0时设置CPU的zero标志位，而且这个标志位是CPU私有的，不会被其它CPU影响。因此，可以执行一次加锁的减操作，再根据CPU的zero标志位来设置本地变量c，并相应返回。
{
unsigned char c;
__asm__ __volatile__(
LOCK "subl %2,%0; sete %1"
："=m" (v->counter),"=qm" (c)
："ir" (i),"m" (v->counter) : "memory");
return c;
}
------------------------------------
#define atomic_read(v) ((v)->counter)
读取v指向的原子变量的值。由于该操作本身就是原子的，只需要一次内存访问就能完成，因此定义为一个宏，并用C代码实现。
#define atomic_set(v,i) (((v)->counter) = (i))
设置v指向的原子变量的值为i。由于该操作本身就是原子的，只需要一次内存访问就能完成，因此定义为一个宏，并用C代码实现。
static __inline__ void atomic_sub(int i,atomic_t *v)
从v指向的原子变量减去i。
static __inline__ void atomic_inc(atomic_t *v)
递增v指向的原子变量。
static __inline__ void atomic_dec(atomic_t *v)
递减v指向的原子变量。
static __inline__ int atomic_dec_and_test(atomic_t *v)
递减v指向的原子变量，并测试是否为0。若为0，返回真，否则返回假。
static __inline__ int atomic_inc_and_test(atomic_t *v)
递增v指向的原子变量，并测试是否为0。若为0，返回真，否则返回假。
static __inline__ int atomic_add_negative(int i,atomic_t *v)
将v指向的原子变量加上i，并测试结果是否为负。若为负，返回真，否则返回假。这个操作用于实现semaphore。