目录
std::atomic ::compare_exchange_weak 和 std::atomic ::compare_exchange_strong
核心原理
函数签名
核心区别
典型用法
1. compare_exchange_weak(循环内重试)
2. compare_exchange_strong(单次尝试)
底层机制
总结
std::atomic<T>::compare_exchange_weak
和 std::atomic<T>::compare_exchange_strong
核心原理
这两个函数都是 原子比较-交换(Compare-and-Swap, CAS) 操作,属于无锁编程的基础操作。其伪代码逻辑如下:
bool compare_exchange(T& expected, T desired) {if (atomic_value == expected) {atomic_value = desired; // 交换成功return true;} else {expected = atomic_value; // 更新 expected 为当前值return false;}
}
关键点:整个操作是原子的(不可中断),用于实现无锁数据结构(如队列、栈)。
函数签名
bool compare_exchange_weak(T& expected, T desired, memory_order success = memory_order_seq_cst,memory_order failure = memory_order_seq_cst);bool compare_exchange_strong(T& expected, T desired,memory_order success = memory_order_seq_cst,memory_order failure = memory_order_seq_cst);
-
expected
:传入期望值,失败时会被更新为原子变量的当前值。 -
desired
:交换成功时设置的目标值。 -
内存序:
success
(成功时的内存序)和failure
(失败时的内存序)。
核心区别
特性 | compare_exchange_weak | compare_exchange_strong |
---|---|---|
虚假失败 | 可能(即使值相等也返回 false ) | 不可能(仅在值不相等时失败) |
性能 | 更高(某些平台减少重试开销) | 稍低(保证严格比较) |
适用场景 | 循环内重试(如自旋锁) | 单次尝试或无循环场景 |
硬件依赖 | 在 ARM/PowerPC 等平台可能虚假失败 | 所有平台行为一致 |
典型用法
1. compare_exchange_weak
(循环内重试)
std::atomic<int> val(10);
int expected = val.load(); // 获取当前值do {int desired = expected * 2; // 计算新值// 弱版本允许虚假失败,需配合循环
} while (!val.compare_exchange_weak(expected, desired));
-
适用场景:自旋锁、无锁队列等需反复重试的操作。
2. compare_exchange_strong
(单次尝试)
std::atomic<bool> flag(false);
bool expected = false;// 仅尝试一次,强版本保证无虚假失败
if (flag.compare_exchange_strong(expected, true)) {// 成功获取锁
} else {// 已被其他线程修改
}
-
适用场景:单次检查或无需重试的逻辑。
底层机制
-
弱版本:
某些硬件(如 ARM)的 CAS 操作可能因缓存一致性协议(如 MESI)或线程调度导致虚假失败,但硬件实现更高效。 -
强版本:
在弱版本基础上封装循环,直到成功或真实失败:
bool compare_exchange_strong(...) {while (!compare_exchange_weak(...)) {if (atomic_value != expected) break; // 真实失败退出}
}
总结
场景 | 推荐函数 |
---|---|
循环内重试(如自旋锁) | compare_exchange_weak |
单次尝试或无循环逻辑 | compare_exchange_strong |
需最高性能(低竞争环境) | weak + 循环 |
需代码简洁性 | strong (避免手动重试) |
最佳实践:
在循环中优先使用 weak
(如实现无锁栈/队列),非循环场景用 strong
。例如:
// 无锁栈的 push 操作
void push(Node* new_node) {Node* old_head = head.load();do {new_node->next = old_head;} while (!head.compare_exchange_weak(old_head, new_node));
}