C++中的CAS(Compare-And-Swap)解读

CAS(Compare-And-Swap)是一种原子操作,用于在多线程编程中实现无锁(lock-free)的线程安全操作。它的核心功能是:检查某个内存位置的值是否与预期值一致,若一致则更新为新值,否则不更新。整个过程是不可分割的原子操作,确保并发安全。


CAS 的工作原理

  1. 输入参数

    • 内存地址:需要操作的目标内存位置。
    • 预期值(expected):认为该内存位置当前应该有的值。
    • 新值(new):若预期值匹配,则更新为的新值。
  2. 操作逻辑

    如果 *内存地址 == 预期值:
        *内存地址 = 新值
        返回 true
    否则:
        返回 false
    

    整个过程是原子性的,不会被其他线程中断。


CAS 的应用场景

  1. 无锁数据结构

    • 实现线程安全的计数器、队列、栈等,避免使用互斥锁(mutex)的性能开销。
    • 示例:多个线程同时更新一个计数器:
      #include <atomic>
      std::atomic<int> counter{0};
      
      void increment() {
          int old_val = counter.load();
          while (!counter.compare_exchange_weak(old_val, old_val + 1)) {
              // 如果失败(其他线程已修改值),重新尝试
          }
      }
      
  2. 解决竞态条件

    • 确保某个操作(如资源分配)在并发环境下只执行一次。
  3. 乐观锁机制

    • 假设并发冲突少,先尝试更新,若失败则重试,避免悲观锁的阻塞。

CAS 的优缺点

优点缺点
无锁操作,减少线程阻塞和上下文切换。可能引发忙等待(循环重试),高竞争时效率低。
适用于低竞争场景,性能高于互斥锁。ABA问题:值被其他线程从A改为B又改回A,CAS误判未修改。
轻量级,适合简单操作(如计数器、标志位)。复杂操作难以用单个CAS实现(需配合其他机制)。

ABA 问题与解决方案

  • ABA问题
    线程1读取内存值为A,线程2将其改为B后又改回A。线程1的CAS操作误认为值未变,导致逻辑错误。

  • 解决方案
    使用带版本号(或标签)的CAS,每次修改递增版本号,确保值的唯一性。
    C++示例

    struct TaggedValue {
        int value;
        int tag;  // 版本号
    };
    std::atomic<TaggedValue> atomic_val;
    
    bool cas(TaggedValue& expected, int new_val) {
        TaggedValue new_struct{new_val, expected.tag + 1};
        return atomic_val.compare_exchange_strong(expected, new_struct);
    }
    

C++ 中的 CAS 操作

C++通过 std::atomic 提供两种CAS函数:

  1. compare_exchange_weak
    可能在某些情况下虚假失败(如硬件架构限制),但性能更高,通常用在循环中重试。

    bool compare_exchange_weak(T& expected, T desired, ...);
    
  2. compare_exchange_strong
    严格保证成功或失败,无虚假失败,但可能更耗资源。

    bool compare_exchange_strong(T& expected, T desired, ...);
    

示例:线程安全的栈(无锁实现片段)

#include <atomic>
template<typename T>
class LockFreeStack {
    struct Node {
        T data;
        Node* next;
    };
    std::atomic<Node*> head;

public:
    void push(const T& data) {
        Node* new_node = new Node{data, nullptr};
        new_node->next = head.load();
        // CAS更新头节点
        while (!head.compare_exchange_weak(new_node->next, new_node));
    }

    bool pop(T& result) {
        Node* old_head = head.load();
        while (old_head && 
               !head.compare_exchange_weak(old_head, old_head->next)) {}
        if (!old_head) return false;
        result = old_head->data;
        delete old_head;
        return true;
    }
};

总结

  • CAS 是并发编程中实现无锁操作的核心机制,通过原子性的“检查-更新”确保线程安全。
  • 适用于简单、高频的低竞争场景(如计数器),但需注意ABA问题和忙等待。
  • 在C++中通过 std::atomic::compare_exchange_weak/strong 使用,结合循环重试实现高效并发。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值