当前位置: 首页 > article >正文

深入解析 CAS 操作

在这里插入图片描述

一、CAS 的本质:硬件级别的乐观锁

CAS(Compare-And-Swap,比较并交换) 是一种原子操作指令,用于实现对共享变量的无锁并发修改。它是现代多核处理器支持的底层硬件指令,也是构建高效并发数据结构(如锁、队列、计数器)的核心基础。

核心原理
  1. 操作原子性:CAS 操作由硬件保证在执行过程中不会被线程调度打断
  2. 三步合一:将"读取-判断-写入"合并为单个原子操作
  3. 乐观锁机制:假设竞争很少发生,先操作后检测冲突
// CAS 伪代码表示
bool CAS(T* ptr, T expected, T new_value) {if (*ptr == expected) {   // 比较内存当前值*ptr = new_value;     // 交换新值return true;}return false;
}

二、工作流程详解

  1. 读取内存值:获取共享变量当前值 V
  2. 计算新值:基于 V 计算目标值 New
  3. 原子提交
    • 若内存值仍为 V ⇒ 写入 New
    • 若内存值已变化 ⇒ 放弃操作

三、关键优势:突破并发瓶颈

特性传统锁机制CAS 机制
线程阻塞可能发生等待无阻塞
死锁风险存在不存在
性能开销上下文切换代价高仅需单条CPU指令
并发粒度粗粒度细粒度

四、ABA 问题:隐藏的陷阱

问题场景
  1. 线程1读取值 A
  2. 线程2修改 A→B→A
  3. 线程1执行 CAS:检测值仍为 A ⇒ 操作成功

后果:数据看似未变,实际已发生中间状态变更

解决方案
  1. 版本号机制
    // Java AtomicStampedReference 实现
    AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0); // 初始版本0ref.compareAndSet("A", "B", 0, 1); // 同时验证值和版本号
    
  2. 时间戳标记:IBM zSeries 的 double-width CAS
  3. 垃圾回收指针:依赖GC防止内存重用(如.NET)

五、编程语言实现案例

Java 的 java.util.concurrent.atomic
// 原子整型自增实现
public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);
}// Hotspot Unsafe 源码实现
public final int getAndAddInt(Object o, long offset, int delta) {int v;do {v = getIntVolatile(o, offset);   // 读取当前值} while (!compareAndSwapInt(o, offset, v, v + delta)); // CAS重试return v;
}
C++11 原子库
#include <atomic>
std::atomic<int> counter(0);// CAS操作实现自增
int old_val = counter.load();
while (!counter.compare_exchange_weak(old_val, old_val + 1)) {// 优化:允许虚假失败,通常配合循环使用
}

六、典型应用场景

  1. 无锁计数器

    # Python ctypes 访问硬件CAS
    import ctypes
    libc = ctypes.cdll.LoadLibrary('libc.so.6')
    counter = ctypes.c_int(0)def atomic_increment():while True:old = counter.valueif libc.__sync_val_compare_and_swap(ctypes.byref(counter), old, old+1) == old:break
    
  2. 无锁栈实现(Treiber Stack)

    class ConcurrentStack<T> {AtomicReference<Node<T>> top = new AtomicReference<>();void push(T item) {Node<T> newHead = new Node<>(item);Node<T> oldHead;do {oldHead = top.get();newHead.next = oldHead;} while (!top.compareAndSet(oldHead, newHead));}T pop() {Node<T> oldHead;Node<T> newHead;do {oldHead = top.get();if (oldHead == null) return null;newHead = oldHead.next;} while (!top.compareAndSet(oldHead, newHead));return oldHead.item;}
    }
    
  3. 无锁队列(Michael-Scott 队列)

    type Node struct {value interface{}next  *Node
    }type Queue struct {head *Nodetail *Node
    }func (q *Queue) Enqueue(v interface{}) {node := &Node{value: v}for {last := q.tailnext := last.nextif last == q.tail { // 验证状态未变if next == nil {if atomic.CompareAndSwapPointer(&last.next, nil, node) {atomic.CompareAndSwapPointer(&q.tail, last, node)return}} else {atomic.CompareAndSwapPointer(&q.tail, last, next)}}}
    }
    

七、底层硬件支持架构

处理器架构CAS 指令位宽支持
x86/x86-64CMPXCHG8/16/32/64位
ARMv8LDXR + STXR(LL/SC模型)64位
POWERlwarx + stwcx64位
RISC-Vlr.w + sc.w32/64/128位

LL/SC(Load-Link/Store-Conditional):现代RISC架构采用的替代实现方案

  1. Load-Link:标记内存区域
  2. 执行计算
  3. Store-Conditional:当标记区域未被修改时写入

八、性能优化策略

  1. 缓存行填充避免伪共享

    // C++ 缓存行对齐结构
    struct alignas(64) AtomicCounter {std::atomic<int> value;char padding[64 - sizeof(std::atomic<int>)];
    };
    
  2. 指数退避减少竞争

    while (!casSuccess) {int delay = random.nextInt(baseDelay);for (int i = 0; i < delay; i++) Thread.yield(); // 让出CPUbaseDelay *= 2; // 指数级增加等待
    }
    
  3. 批量操作减少CAS调用

    // 批量增加计数器
    func (c *Counter) Add(n int) {const batchSize = 32for n > 0 {batch := nif batch > batchSize {batch = batchSize}// 单次CAS更新批量值c.accumulate(batch) n -= batch}
    }
    

九、局限性及替代方案

  1. 循环开销问题:高竞争场景下自旋消耗CPU

    • 解决方案:java.util.concurrent.locks.LockSupport.park()
  2. 单一变量限制:无法原子修改多个独立变量

    • 替代方案:事务内存(Transactional Memory)
  3. 优先级颠倒风险:低优先级线程持有CAS导致高优先级饥饿

    • 实时系统解决方案:优先级继承协议
  4. 内存顺序约束

    // C++ 内存顺序控制
    counter.compare_exchange_weak(old_val, new_val,std::memory_order_acq_rel,  // 成功时的内存序std::memory_order_acquire   // 失败时的内存序
    );
    

十、现代发展方向

  1. 128位 CAS 扩展:用于原子更新指针+元数据(如指针标记)

    bool __atomic_compare_exchange_16(void* ptr, __int128* expected,__int128 desired
    );
    
  2. 持久内存 CAS:Intel Optane PMEM 的持久化原子操作

    bool pmemobj_atomic_compare_exchange(PMEMoid *ptr, uint64_t *expected_oid,uint64_t desired_oid
    );
    
  3. GPU 原子操作:NVIDIA CUDA 的全局内存原子CAS

    int atomicCAS(int* address, int compare, int val);
    
  4. 分布式 CAS:跨多节点的分布式原子操作协议

    参与者 → 协调者:CAS请求
    协调者 → 所有节点:预提交
    节点响应符合条件 → 协调者:投票
    多数同意 → 协调者:提交指令
    

总结:CAS 的核心价值

CAS 操作通过硬件级原子指令,实现了:

  • 无锁并发:消除传统锁的开销
  • 非阻塞算法:提升系统响应能力
  • 细粒度同步:实现高性能并发数据结构

尽管存在 ABA 问题、高竞争场景性能下降等局限,但通过版本号机制、缓存优化等手段可有效缓解。作为现代并发编程的基石,CAS 在操作系统内核、数据库系统、中间件等高性能系统中发挥着不可替代的作用。理解其原理和最佳实践,是构建高性能并发系统的必备技能。

http://www.lryc.cn/news/2404948.html

相关文章:

  • vue3+TS+eslint9配置
  • 【bug】Error: /undefinedfilename in (/tmp/ocrmypdf.io.9xfn1e3b/origin.pdf)
  • HarmonyOS5.0——CodeGenie:鸿蒙生态的AI编程革命​
  • 【Dv3Admin】系统视图字典管理API文件解析
  • 免费 SecureCRT8.3下载、安装、注册、使用与设置
  • Redis :String类型
  • 两种Https正向代理的实现原理
  • 第18节 Node.js Web 模块
  • 网络爬虫一课一得
  • LeetCode--24.两两交换链表中的结点
  • 嵌入式SDK技术EasyRTC音视频实时通话助力即时通信社交/教育等多场景创新应用
  • IDEA集成JRebel插件,实现实时热部署
  • 1-3 Linux-虚拟机(2025.6.7学习篇- mac版本)
  • 如何打造一款金融推理工具Financial Reasoning Workflow:WebUI+Ollama+Fin-R1+MCP/RAG
  • mybatis的if判断==‘1‘不生效,改成‘1‘.toString()才生效的原因
  • 【试卷篇】Spring面试试卷题
  • 通过阿里云 DashScope API 调用通义千问
  • Go 中 map 的双值检测写法详解
  • 大故障:阿里云核心域名爆炸了
  • 解决Zotero翻译插件Zotero PDF Translate无法正常翻译
  • 【Latex】Windows/Ubuntu 绘制 eps 矢量图通用方法(drawio),支持插入 Latex 数学公式
  • Vue---vue使用AOS(滚动动画)库
  • 十(1). 强制类型转换
  • 从npm库 Vue 组件到独立SDK:打包与 CDN 引入的最佳实践
  • rknn优化教程(一)
  • uniapp Vue2 获取电量的独家方法:绕过官方插件限制
  • 【统计方法】树模型,ensemble,bagging, boosting
  • 【选配电脑】CPU核显工作机控制预算5000
  • Mysql 插入中文乱码
  • UserAgent包名识别工具