cmpxchg 与 CAS 循环

这页讲的是:有些并发更新不是简单加减一个数,而是“如果对象还保持旧样子,就把它换成新样子;如果已经被别人改过,就重新看局面再决定”。学这页的重点,是理解 cmpxchg 更像一种带条件的原子替换,它常把并发修改写成“尝试—失败—重试”的 CAS 循环。

这块是什么

cmpxchg 与 CAS 循环,讲的是 Linux 怎样在并发更新里先比较当前值是否还是自己预期的旧值,若是就原子地换成新值,若不是就说明局面已变,需要重新读取并再试一次。它关注的是“带前提条件的原子替换”,而不是单纯把某个计数加一减一。

可以把它理解成:你准备把白板上的 A 改成 B,但前提是白板上现在还真的是 A。如果已经被别人改成 C,就不能硬写 B,而要先重新理解现场再决定。

它负责什么

把条件判断和替换绑成一个整体

  • 很多并发更新不能只改值,还要先确认“局面没变”
  • cmpxchg 把比较旧值和写入新值捆成原子动作
  • 避免中间被别人抢先改变状态
  • 让条件式更新真正站得住

支撑失败后重试的无锁写法

  • 如果条件不成立,不代表系统坏了
  • 常见做法是重新读取状态再尝试
  • 把并发竞争显式变成“失败就重算”的循环
  • 让某些轻量更新不必总靠大锁保护

给状态机切换提供精细入口

  • 很多状态跳转都只允许从特定旧状态进入新状态
  • cmpxchg 非常适合表达这种“只在旧状态匹配时推进”
  • 让状态机边界更清楚
  • 避免两个执行者都以为自己成功切换了状态

为什么它不是“原子操作的花哨版本”

如果想得太简单会怎样真正关键在哪
觉得只是多一个 API 形式会看不见它真正表达的是“只有前提还成立时才允许替换”。它的价值在条件式原子更新,不在名字更复杂。
把失败当异常会误解 CAS 循环的正常工作方式。失败常是并发竞争的自然结果,重试才是设计的一部分。
觉得这样就完全无锁无脑更快会漏掉高竞争下重试成本可能很高。CAS 循环更轻不等于永远更省。
只看单变量替换会低估它经常承载的是状态机入口和对象发布边界。cmpxchg 常在更大协议里扮演关键门闩。

关键概念

概念现在怎么理解
cmpxchg先比较旧值是否匹配,再决定是否原子替换成新值的操作。
CAS 循环失败就重新读取状态、重新计算、再尝试替换的一类写法。
条件式更新不是无条件写新值,而是只有局面仍符合预期才推进。
竞争失败别人先一步改了值,自己这次尝试需要重来,并不等于系统出错。
状态门闩很多状态切换都把 cmpxchg 当成“只有一个人能抢到入口”的门闩。

为什么重要

常见误解

它不负责什么

和其他模块的关系

相关模块关系
atomic operationscmpxchg 是更有条件语义的一类原子动作,比普通加减更常用于状态切换。
memory barriers替换成功后,别人何时按什么顺序看到新状态和相关数据,常要继续看顺序语义。
refcount_t很多“只有对象仍可持有时才安全加引用”的思路,都和条件式更新非常接近。
锁与无锁路径它常出现在试图避免大锁、但又要保住最小正确性边界的设计里。

读完这页后,你应该能回答

后面适合继续问:cmpxchg 和 atomic_add_return 最容易混在哪?高竞争下 CAS 循环为什么可能比上锁还难看?对象指针替换为什么常要把 cmpxchg 和生命周期规则一起看?