test-and-set 修改一个内存位置的内容,并作为一个单一的原子操作返回其旧值。
compare-and-swap 原子地比较一个内存位置的内容和一个给定的值,只有当它们相同时,才将该内存位置的内容修改为一个给定的新值。
TAS(Test And Set)
test-and-set指令: 作为一个原子不被中断的操作指令,在硬件设计上,仅允许同一时间一个处理器执行该指令,从而保证了它的单一原子性操作。
提供的操作是:
1) 把给定的内存地址设置为 1
2) 然后返回之前的旧值
// 伪代码
// 只要保证了 start ,end 期间单处理器执行,且不被打断,就算实现指令的原子性
int test_and_set(volatile int *lockPtr){
int oldValue;
// --- start of atomic segment ---
oldValue=*lockPtr;
*lockPtr=1;
// --- end of atomic segment ---
return oldValue;
// spinlock 伪代码
volatile int plock=0;
void lock(){
while (test_and_set(&plock)==1){}
void unlock(){
plock=0;
lock();
// only one process can be in the section
unlock();
CAS(Compare and Swap)
CAS同样是一个同步指令,主要被用于多线程同步;
它的处理过程类似:
判断reg上值和输入old值是否一致,一致时改reg值为new
返回reg上的原值
compare-and-swap,同test-and-set相比,它使用的输入寄存器更多一些,同时它返回值的存储信息也更丰富一些;
// 伪代码
// 保证了start,end其间原子执行,就实现了指令的原子性
int compare_and_swap(int* regPtr, int oldv, int newv){
int org_reg_value;
// --- start of atomic segment ---
org_reg_value = *regPtr;
if (org_reg_value == oldv){
*regPtr = newv;
// --- end of atomic segment ---
return org_reg_value;
test-and-set使用了一个bit位作为目标设定值,表达0/1两个信息量。
compare-and-swap可以用32位或64位作为设定值,输出值,能表达更多的信息量。
可以用来做原子添加增量值的设置,样例实现:
// 伪代码
int add(int *ptr, int add){
int org_value = *ptr;
while(compare_and_swap(ptr, org_value, org_value+add) != org_value){
org_value = *ptr;
return org_value + add;
当然也可以用来实现自旋锁,样例实现:
// 伪代码
volatile int lock = 0;
void lock(){
while(compare_and_swap(&lock, 0, 1) == 0){}
void unlock(){
lock = 0;
lock();
critical section // only one process can be in the section at a time
unlock();
// 基于 CAS//TAS 实现无锁等待
template<class T>
void lock(lock_t<T> *lock){
// CAS
while(CAS(lock->flag,0,1)==0){
// 保存线程TCB,将运行的线程 TCB 插入等待队列
// 线程设置为等待状态,调度程序
template<class T>
void unlock(lock_t<T> *lock){