贝利信息

c# Interlocked.CompareExchange 的用法和CAS原子操作原理

日期:2026-01-13 00:00 / 作者:幻夢星雲
Interlocked.CompareExchange 通过 CPU 硬件级原子指令(如 x86 的 CMPXCHG)实现不可分割的“读取→比较→写入”,返回原始值以供判断成败,失败时不写入、不抛异常;典型用于自旋等待、状态机切换和一次性初始化。

Interlocked.CompareExchange 是怎么实现“比较后交换”的

它不是简单的 if-else,而

是一条 CPU 硬件级原子指令(如 x86 的 CMPXCHG),整个“读取→比较→写入”三步不可分割。哪怕两个线程同时执行 Interlocked.CompareExchange(ref _state, 1, 0),也只会有一个成功把 _state 从 0 改成 1,另一个拿到旧值 0 后直接返回,不修改内存。

常见用法:自旋等待、无锁计数器、状态机切换

它最典型的模式是“循环重试”,也就是 CAS 自旋(spin loop)。比如等待某个整型标志位从 expected 变成 desired

while (Interlocked.CompareExchange(ref _ready, 1, 0) == 0)
{
    // 还没就绪,继续等(可加 Thread.SpinWait 或小延时防空转)
}

容易踩的坑:ABA 问题、内存顺序、类型混淆

CompareExchange 本身不解决 ABA 问题:假设变量从 A→B→A,CAS 会误认为“始终是 A”而成功交换,但中间状态已被篡改。C# 中没有内置带版本号的 AtomicStampedReference,得自己用 long 高 32 位存版本号、低 32 位存值来模拟。

和 Interlocked.Exchange 的关键区别在哪

Exchange 是“无条件覆盖”,CompareExchange 是“有条件覆盖”。前者适合设置标志位、替换缓存对象;后者才是真正的 CAS 原语,用于构建更复杂的同步逻辑。

真正难的从来不是调用这行代码,而是想清楚:你要保护的到底是“一个值”,还是“一段状态变迁过程”。CAS 给你的是原子性,不是逻辑正确性——循环条件、重试策略、ABA 防御,都得自己兜底。