c# C#中的CAS(Compare-and-Swap)操作和Interlocked类的关系

来源:这里教程网 时间:2026-02-21 17:36:35 作者:

Interlocked类就是C#中CAS操作的官方实现载体

C#不提供裸露的CAS指令语法(比如像Java的

Unsafe.compareAndSwapInt
),所有线程安全的“读-改-写”原子操作都必须通过
Interlocked
类完成。它底层直接映射到CPU的
CMPXCHG
等指令,在x86/x64上是真正的硬件级CAS,不是软件模拟。

Interlocked.CompareExchange是最贴近CAS语义的核心方法

Interlocked.CompareExchange
就是C#里唯一对应经典CAS三参数模型(地址、预期值、新值)的API。它返回旧值,并仅在旧值等于预期值时才写入新值。

int value = 100;
int expected = 100;
int newValue = 200;
// 原子执行:如果value当前是100,则设为200,返回100;否则返回当前实际值
int oldValue = Interlocked.CompareExchange(ref value, newValue, expected);
返回值是内存位置**操作前的实际值**,不是布尔结果——这是初学者最常误解的一点 必须用
ref
传递变量地址,不能传值或属性(属性不是存储位置)
支持
int
long
IntPtr
、引用类型(
object
或泛型
T
,T需为引用类型)
short
byte
等小整型没有直接重载,需转为
int
再操作,或用
Interlocked.Add
等替代

CompareExchange和Add/Increment等其他Interlocked方法的区别

Interlocked.Add
Interlocked.Increment
等看似更“高级”的方法,其实内部仍基于CAS循环(自旋)实现,只是封装了常见模式。它们不是独立原子指令,而是
CompareExchange
的衍生用法。

Interlocked.Increment(ref i)
≈ 循环调用
CompareExchange
直到成功,避免手动写CAS自旋逻辑
但如果你需要“比较后条件性更新+获取旧值”这个完整语义,只能用
CompareExchange
,其他方法不返回原值
性能上,简单计数场景用
Increment
更简洁;复杂条件更新(如无锁栈Push/Pop、状态机跃迁)必须用
CompareExchange

容易踩的坑:引用类型CAS的陷阱

对引用类型使用

CompareExchange<t></t>
时,比较的是**引用相等性(reference equality)**,不是内容相等。且T必须是引用类型(或用
class
约束的泛型)。

var obj1 = new object();
var obj2 = new object();
object current = obj1;
// 下面这行永远失败:obj2 != obj1(引用不同),即使它们都是空object()
Interlocked.CompareExchange(ref current, obj2, obj1); // 返回obj1,current不变
// 正确用法:用同一个引用做预期值
object expected = obj1;
Interlocked.CompareExchange(ref current, new object(), expected);
不能对值类型(如
struct
)直接使用泛型
CompareExchange<t></t>
,会编译报错
不要把
CompareExchange
当成“线程安全的赋值”——它只在条件满足时才写,不满足就什么也不做
在高竞争场景下,
CompareExchange
可能多次失败,需配合循环逻辑(如无锁队列中的retry loop)

真正难的从来不是调用

Interlocked
,而是设计出正确、可终止、无ABA问题的无锁算法结构——库函数只提供砖块,砌墙还得自己画图。

相关推荐