std::atomic<T>::compare_exchange_weak, std::atomic<T>::compare_exchange_strong
bool compare_exchange_weak( T& expected, T desired, std::memory_order success, |
(1) | (C++11 起) |
bool compare_exchange_weak( T& expected, T desired, std::memory_order success, |
(2) | (C++11 起) |
bool compare_exchange_weak( T& expected, T desired, std::memory_order order = |
(3) | (C++11 起) |
bool compare_exchange_weak( T& expected, T desired, std::memory_order order = |
(4) | (C++11 起) |
bool compare_exchange_strong( T& expected, T desired, std::memory_order success, |
(5) | (C++11 起) |
bool compare_exchange_strong( T& expected, T desired, std::memory_order success, |
(6) | (C++11 起) |
bool compare_exchange_strong( T& expected, T desired, std::memory_order order = |
(7) | (C++11 起) |
bool compare_exchange_strong( T& expected, T desired, std::memory_order order = |
(8) | (C++11 起) |
原子地比较 *this 和 expected 的对象表示 (C++20 前)值表示 (C++20 起)。如果它们逐位相等,那么以 desired 替换前者(进行读修改写操作)。否则,将 *this 中的实际值加载进 expected(进行加载操作)。
重载 | 读修改写操作的内存模型 | 加载操作的内存模型 |
---|---|---|
(1,2,5,6) | success | failure |
(3,4,7,8) | order |
|
如果 failure 强于 success 或者 (C++17 前)是 std::memory_order_release 和 std::memory_order_acq_rel 之一,那么行为未定义。
任何 volatile 重载在参与重载决议且 std::atomic<T>::is_always_lock_free 是 false 时被弃用。 |
(C++20 起) |
参数
expected | - | 到期待在原子对象中找到的值的引用 |
desired | - | 在符合期待时存储到原子对象的值 |
success | - | 读修改写操作所用的内存同步定序 |
failure | - | 加载操作所用的内存同步定序 |
order | - | 两个操作所用的内存同步定序 |
返回值
成功更改底层原子值时返回 true,否则为返回 false。
注解
比较和复制是逐位的(类似 std::memcmp 和 std::memcpy);不使用构造函数、赋值运算符或比较运算符。
允许 compare_exchange_weak
假性失败,即即使它们相等也表现如同 *this != expected。在循环中进行比较和交换时,compare_exchange_weak
在有的平台上会产出更好的性能。
当 compare_exchange_weak
比较和交换会要求循环,而 compare_exchange_strong
不要求时,推荐用 std::compare_exchange_strong
,除非 T
的对象表示可包含填充位、 (C++20 前)陷阱位或为同一值提供多个对象表示(例如浮点 NaN)。这些情况下,compare_exchange_weak
一般均可用,因为它在一些稳定对象表示上快速收敛。
对于联合体,如果它持有某些只有部分成员的值表示有参与的位,那么比较和交换可能总会失败,因为这种填充位在不参与活跃成员的值表示时拥有不确定值。
忽略决不参与对象值表示的填充位。 |
(C++20 起) |
示例
比较和交换操作通常用作免锁数据结构的基本组成部分。
#include <atomic> template<typename T> struct node { T data; node* next; node(const T& data) : data(data), next(nullptr) {} }; template<typename T> class stack { std::atomic<node<T>*> head; public: void push(const T& data) { node<T>* new_node = new node<T>(data); // 将 head 的当前值放到 new_node->next 中 new_node->next = head.load(std::memory_order_relaxed); // 现在令 new_node 为新的 head ,但如果 head 不再是 // 存储于 new_node->next 的值(某些其他线程必须在刚才插入结点) // 那么将新的 head 放到 new_node->next 中并再尝试 while(!head.compare_exchange_weak(new_node->next, new_node, std::memory_order_release, std::memory_order_relaxed)) ; // 循环体为空 // 注意:上述使用至少在这些版本不是线程安全的 // 先于 4.8.3 的 GCC(漏洞 60272),先于 2014-05-05 的 clang(漏洞 18899) // 先于 2014-03-17 的 MSVC(漏洞 819819)。下面是变通方法: // node<T>* old_head = head.load(std::memory_order_relaxed); // do // { // new_node->next = old_head; // } // while (!head.compare_exchange_weak(old_head, new_node, // std::memory_order_release, // std::memory_order_relaxed)); } }; int main() { stack<int> s; s.push(1); s.push(2); s.push(3); }
演示 std::compare_exchange_strong
如何要么更改原子对象的值,要么将变量用于比较。
本节未完成 原因:强 CAS 的更实际用法会更好,例如在 Concurrency in Action 使用它的地方 |
#include <atomic> #include <iostream> std::atomic<int> ai; int tst_val = 4; int new_val = 5; bool exchanged= false; void valsout() { std::cout << "ai = " << ai << " tst_val = " << tst_val << " new_val = " << new_val << " exchanged = " << std::boolalpha << exchanged << "\n"; } int main() { ai= 3; valsout(); // tst_val != ai ==> tst_val 被修改 exchanged= ai.compare_exchange_strong(tst_val, new_val); valsout(); // tst_val == ai ==> ai 被修改 exchanged= ai.compare_exchange_strong(tst_val, new_val); valsout(); }
输出:
ai = 3 tst_val = 4 new_val = 5 exchanged = false ai = 3 tst_val = 3 new_val = 5 exchanged = false ai = 5 tst_val = 3 new_val = 5 exchanged = true
参阅
原子地比较原子对象和非原子实参的值,相等时进行原子交换,不相等时进行原子加载 (函数模板) |