Since the C++11 standard, the Concurrency Support Library includes built-in support for threads (std::thread
) with atomic operations (std::atomic
). C++11 provides both weak and strong compare-and-exchange operations in multi-threading applications. Since C++11, weak compare and exchange are used in modern C++ standards such as C++14, C++17, C++20, and in other new standards. In this post, we explain weak compare and exchange with simple examples.
What is weak compare and exchange in C++?
The Weak Compare and Exchange template atomically compares the value pointed to by the atomic object with the value pointed to by expected. This feature comes with C++11 and is used in other modern C++ standards. and performs the following operations based on the comparison results:
- If the comparison result is true (bitwise-equal), the function replaces the value pointed to by the atomic object with the value desired.
- If the comparison result is false, the function updates the value in expected with the value pointed by the atomic object
There are two most common syntaxes for the compare_exchange_weak
, first,
1 2 3 |
bool compare_exchange_weak( T& expected, T desired) noexcept; |
and in weak compare and exchange atomic operations, we can use std::compare_exchange_weak
template with memory order types.
Here is the syntax for the compare_exchange_weak
with memory orders,
1 2 3 4 5 |
bool compare_exchange_weak( T& expected, T desired, std::memory_order success, std::memory_order failure ) noexcept; |
here is how we can use it,
1 2 3 4 5 6 7 |
std::atomic<int> x; exchanged = x.compare_exchange_weak( expected, desired); exchanged = x.compare_exchange_weak( expected, desired, std::memory_order_release, std::memory_order_relaxed); |
Note that, providing both compare_exchange_strong
and compare_exchange_weak
allow us to decide whether we want the library to handle spurious failures (using compare_exchange_strong
) or if we want to handle it in our own code (using compare_exchange_weak
). The compare_exchange_strong
needs extra overhead to retry in the case of failure. For details please see Load-link/store-conditional in Wikipedia.
Is there a simple example of weak compare and exchange in C++?
Here is a simple example about weak compare and exchange in C++.
Let’s assume we have a thread function myf1()
that ensures value is changed after a weak compare and exchange. This is how we can do this,
1 2 3 4 5 6 7 8 9 10 11 12 13 |
void myf1(int desired) { int expected = 1; bool exchanged; do { exchanged = x.compare_exchange_weak( expected, desired ); std::cout << x.load() << ","; }while (!exchanged); } |
Is there a full example of weak compare and exchange in modern C++?
Let’s assume we have a thread function myf1()
that ensures value is changed after a weak compare and exchange. Let’s change after 1 second with myf2()
. Here is the full example about weak compare and exchange in C++.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
#include <iostream> #include <atomic> #include <thread> std::atomic<int> x = 0; void myf1(int desired) { int expected = 1; bool exchanged; do { exchanged = x.compare_exchange_weak( expected, desired ); std::cout << x.load() << ","; }while (!exchanged); std::cout << " myf1 done, "; } void myf2() { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); x.store(5); } int main() { std::cout << "x= "; std::thread t1 (myf1, 7); std::thread t2 (myf2); t1.join(); t2.join(); std::cout << "x= " << x.load() << std::endl; system("pause"); return 0; } |
The output will be as follows.
1 2 3 4 |
x= 0,7, myf1 done, x= 5 Press any key to continue . . . |
As you see weak compare-and-exchange operation is an atomic operation that can be used in multi-threaded applications to achieve synchronization. For more information about this strong and weak compare and exchange feature, see Strong Compare and Exchange Proposal document.
C++ Builder is the easiest and fastest C and C++ IDE for building simple or professional applications on the Windows, MacOS, iOS & Android operating systems. It is also easy for beginners to learn with its wide range of samples, tutorials, help files, and LSP support for code. RAD Studio’s C++ Builder version comes with the award-winning VCL framework for high-performance native Windows apps and the powerful FireMonkey (FMX) framework for cross-platform UIs.
There is a free C++ Builder Community Edition for students, beginners, and startups; it can be downloaded from here. For professional developers, there are Professional, Architect, or Enterprise version.