“Herlihy 层级的经典分类包括:原子读写寄存器的共识数为 $1$;test and set、swap 与 fetch and add 的共识数为 $2$;标准比较并交换(CAS)的共识数…”
形式陈述
本条规定不会伪失败的强比较并交换(strong CAS),可视为只有一种条件更新方法的并发对象;它是作用于共享位置
比较与写入之间不存在其他线程可插入的窗口,这是它区别于"先读后写"两步序列的全部要点。定义只约束该位置上值的相等性判断与条件写入;跨位置的内存排序(如 acquire/release 语义)由具体硬件或语言接口另行规定,不属于 CAS 本身。
直觉
CAS 把乐观并发的哲学压缩进一条指令:线程不加锁地读取共享状态、在私有空间算出新状态,提交时声明"仅当世界仍是我看到的样子才生效"。若其他线程已抢先修改,提交失败,线程重读重算再试。与悲观的锁相比,它在提交时检查当前值是否仍与预期相等,而不是阻止其他人更新;没有冲突时一次尝试即可成功,遇到不匹配时算法可以重读再试。相等性检查并不检测全部修改历史,后面的 ABA 例子正说明这一边界。这个原语为非阻塞进展提供了工具,但进展性属于整个算法,而不属于 CAS 本身;在所有更新都经 CAS 提交的 lock-free 算法里,一次失败可作为其他线程已改变共享状态的证据,而用 CAS 实现的自旋锁仍可能在持锁线程停顿时卡住所有等待者。
例子与边界
正例是无锁计数器:线程读出
无锁栈的压入更能看出 CAS 如何保护复合结构:线程先读取旧栈顶,把新节点的 next 指向旧顶,再尝试把栈顶从旧值换成新节点;失败说明这段时间里栈已经变化,必须重读后重做。成功的 CAS 通常就是线性化一致性证明中的线性化点,整个压入操作可视为在这一瞬间生效。
实际语言接口还可能提供 weak CAS,允许当前值与预期相等却返回失败;此时一次失败不能证明其他线程已经成功修改状态。弱 CAS 的循环与进展分析应采用其完整接口合同,不能直接套用本页强 CAS 的失败见证。
边界之一是 ABA 问题:CAS 判断的是"值相等"而非"未被动过"。若
推论与应用
CAS 是现代同步设施的枢纽原语:无锁栈与队列、原子引用、一次性初始化、自旋锁与其他互斥实现都以它为骨架,主流指令集与并发库均直接提供。CAS 在标准原子语义下具有无限共识数;这项分类、通用构造与低层对象不可能性统一由共识数与 Wait-free 层级说明,本页只保留 CAS 的操作规格、算法用法与 ABA 边界。
lock-free 进展的大量正面结果依赖 CAS 或同等强度原语,但一条 CAS 指令本身不赋予整个调用路径任何进展等级。重试策略、帮助机制和内存回收都必须一并分析。
若更新还要受另一个控制字约束,RDCSS用可帮助描述符完成“控制仍匹配时修改一个数据字”。多字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。