“边界情形之一是复合操作:先原子地读 $x$、再在 $x$ 满足条件时原子地写,这两步各自原子,但整体不原子——另一线程可在两步之间修改 $x$,造成 check then act 竞态。消除…”
形式陈述 ​
比较并交换(CAS)可视为只有一种条件更新方法的并发对象;它是作用于共享位置
比较与写入之间不存在其他线程可插入的窗口,这是它区别于"先读后写"两步序列的全部要点。定义只约束该位置上值的相等性判断与条件写入;跨位置的内存排序(如 acquire/release 语义)由具体硬件或语言接口另行规定,不属于 CAS 本身。
直觉
CAS 把乐观并发的哲学压缩进一条指令:线程不加锁地读取共享状态、在私有空间算出新状态,提交时声明"仅当世界仍是我看到的样子才生效"。若其他线程已抢先修改,提交失败,线程重读重算再试。与悲观的锁相比,它把"防止别人插手"换成了"检测别人是否插过手":无竞争时零等待,有竞争时以重试为代价。这个原语为非阻塞进展提供了工具,但进展性属于整个算法,而不属于 CAS 本身;在所有更新都经 CAS 提交的 lock-free 算法里,一次失败可作为其他线程已改变共享状态的证据,而用 CAS 实现的自旋锁仍可能在持锁线程停顿时卡住所有等待者。
例子与边界
正例是无锁计数器:线程读出
无锁栈的压入更能看出 CAS 如何保护复合结构:线程先读取旧栈顶,把新节点的 next 指向旧顶,再尝试把栈顶从旧值换成新节点;失败说明这段时间里栈已经变化,必须重读后重做。成功的 CAS 通常就是线性化一致性证明中的线性化点,整个压入操作可视为在这一瞬间生效。
边界之一是 ABA 问题:CAS 判断的是"值相等"而非"未被动过"。若
推论与应用
CAS 是现代同步设施的枢纽原语:无锁栈与队列、原子引用、一次性初始化、自旋锁与其他互斥实现都以它为骨架,主流指令集与并发库均直接提供。CAS 在标准原子语义下具有无限共识数;这项分类、通用构造与低层对象不可能性统一由共识数与 Wait-free 层级说明,本页只保留 CAS 的操作规格、算法用法与 ABA 边界。
lock-free 进展的大量正面结果依赖 CAS 或同等强度原语,但一条 CAS 指令本身不赋予整个调用路径任何进展等级。重试策略、帮助机制和内存回收都必须一并分析。
参考资料
- Maurice Herlihy and Nir Shavit, The Art of Multiprocessor Programming, rev. 1st ed., Morgan Kaufmann, 2012,Chs. 1–18。
- Hagit Attiya and Jennifer Welch, Distributed Computing: Fundamentals, Simulations, and Advanced Topics, 2nd ed., Wiley, 2004,Chs. 1–18。