| Defined in header <atomic> | ||
|---|---|---|
| (1) | (since C++11) | |
bool compare_exchange_weak( T& expected, T desired,
std::memory_order success,
std::memory_order failure ); | ||
bool compare_exchange_weak( T& expected, T desired,
std::memory_order success,
std::memory_order failure ) volatile; | ||
| (2) | (since C++11) | |
bool compare_exchange_weak( T& expected, T desired,
std::memory_order order =
std::memory_order_seq_cst ); | ||
bool compare_exchange_weak( T& expected, T desired,
std::memory_order order =
std::memory_order_seq_cst ) volatile; | ||
| (3) | (since C++11) | |
bool compare_exchange_strong( T& expected, T desired,
std::memory_order success,
std::memory_order failure ); | ||
bool compare_exchange_strong( T& expected, T desired,
std::memory_order success,
std::memory_order failure ) volatile; | ||
| (4) | (since C++11) | |
bool compare_exchange_strong( T& expected, T desired,
std::memory_order order =
std::memory_order_seq_cst ); | ||
bool compare_exchange_strong( T& expected, T desired,
std::memory_order order =
std::memory_order_seq_cst ) volatile; |
Atomically compares the object representation of *this with the object representation of expected, as if by std::memcmp, and if those are bitwise-equal, replaces the former with desired (performs read-modify-write operation). Otherwise, loads the actual value stored in *this into expected (performs load operation). Copying is performed as if by std::memcpy.
The memory models for the read-modify-write and load operations are success and failure respectively. In the (2) and (4) versions order is used for both read-modify-write and load operations, except that std::memory_order_acquire and std::memory_order_relaxed are used for the load operation if order == std::memory_order_acq_rel, or order == std::memory_order_release respectively.
Parameters
| expected | - | reference to the value expected to be found in the atomic object |
| desired | - | the value to store in the atomic object if it is as expected |
| success | - | the memory synchronization ordering for the read-modify-write operation if the comparison succeeds. All values are permitted. |
| failure | - | the memory synchronization ordering for the load operation if the comparison fails. Cannot be std::memory_order_release or std::memory_order_acq_rel and cannot specify stronger ordering than success |
| order | - | the memory synchronization ordering for both operations |
Return value
true if the underlying atomic value was changed, false otherwise.
Exceptions
noexcept specification: noexceptNotes
The weak forms (1-2) of the functions are allowed to fail spuriously, that is, act as if *this != expected even if they are equal. When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms.
When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable unless the object representation of T may include padding bits, trap bits, or offers multiple object representations for the same value (e.g. floating-point NaN). In those cases, weak compare-and-exchange typically works because it quickly converges on some stable object representation.
Example
compare and exchange operations are often used as basic building blocks of lockfree data structures.
#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);
// put the current value of head into new_node->next
new_node->next = head.load(std::memory_order_relaxed);
// now make new_node the new head, but if the head
// is no longer what's stored in new_node->next
// (some other thread must have inserted a node just now)
// then put that new head into new_node->next and try again
while(!head.compare_exchange_weak(new_node->next, new_node,
std::memory_order_release,
std::memory_order_relaxed))
; // the body of the loop is empty
// Note: the above use is not thread-safe in at least
// GCC prior to 4.8.3 (bug 60272), clang prior to 2014-05-05 (bug 18899)
// MSVC prior to 2014-03-17 (bug 819819). The following is a workaround:
// 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);
}Demonstrates how compare_exchange_strong either changes the value of the atomic variable or the variable used for comparison.
#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 is modified
exchanged= ai.compare_exchange_strong( tst_val, new_val );
valsout();
// tst_val == ai ==> ai is modified
exchanged= ai.compare_exchange_strong( tst_val, new_val );
valsout();
return 0;
}Output:
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
See also
| atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not (function template) |
Please login to continue.