在 C++ 中,CAS(Compare-And-Swap)操作主要通过 <atomic> 头文件中的 std::atomic 类模板提供的成员函数来实现。理解其底层逻辑对于编写高性能并发代码至关重要。
1. CAS 的核心逻辑
CAS 操作本质上包含三个关键要素:
内存值 (V):要更新的变量当前存储的值。 预期原值 (E, Expected):线程读取时认为该变量应该有的值(通常是之前的快照)。 新值 (N, New):线程希望写入的新数据。
操作流程遵循比较、交换、重试的循环模式:
- 比较:检查内存位置 V 的当前值是否等于预期值 E。
- 交换(如果相等):若
V == E,说明在此期间没有其他线程修改过该变量,则将 V 更新为新值 N。操作成功,返回true。 - 重试/失败(如果不相等):若
V != E,说明有其他线程抢先修改了变量。此时不进行更新,并将内存中的最新值 V 赋值给预期值 E(这样下次重试时就有了最新的参照)。操作失败,返回false。
2. C++ 中的 CAS 函数
std::atomic 提供了两个版本的 CAS 实现,选择哪一个取决于具体场景。
A. compare_exchange_weak(弱 CAS)
即使内存中的值与预期值相等,它也可能返回 false,这被称为'伪失败'。
原因在于某些硬件架构(如 ARM、PowerPC)上,CAS 是通过 LL/SC(Load-Linked/Store-Conditional)指令实现的。上下文切换或其他中断可能导致 SC 指令意外失败。
适用场景:循环算法。因为在循环中,伪失败只会导致多一次循环迭代,而
weak版本在某些平台上通常比strong版本性能更高。
B. compare_exchange_strong(强 CAS)
只有当内存值确实不等于预期值时才会返回 false。
适用场景:非循环的操作,或者当重试的代价非常昂贵时。它在内部可能已经包含了一个小循环来处理伪失败。
3. 代码示例:标准的 CAS 循环
这是最经典的使用模式,用于原子地修改一个变量,例如向栈中压入一个元素。
#include <atomic>
#include <iostream>
struct Node {
int data;
Node* next;
};
std::atomic<Node*> head(nullptr);
{
Node* new_node = Node{data, };
Node* expected = head.();
{
new_node->next = expected;
} (!head.(expected, new_node));
}


