TAS 和 CAS 对比及伪代码

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){