std atomic ref in C++
Introduction:
In multithreaded programming, race conditions must be avoided, and data integrity must be guaranteed. The std::atomic_ref template in C++ helps with concurrent environments by handling shared data. In this article, you will learn about the std::atomic_ref with its uses, advantages, and best practices.
What is the std::atomic_ref?
The std::atomic_ref is a C++ template, which is introduced in C++20. It facilitates atomic access to shared variables and ensures that operations on these variables are indivisible and thread-safe. It is designed to be a safer and more flexible alternative to std::atomic, allowing atomic operations on non-atomic types and enabling lock-free concurrent algorithms.
Similar to language references, std::atomic_ref constness is shallow; a const std::atomic_ref object allows one to change the referred value.
Defined in header <atomic>
template< class T >
struct atomic_ref;
template< class T >
struct atomic_ref<T*>;
Declaring std::atomic_ref:
Include the <atomic> header file to use the std::atomic_ref function.
Syntax:
It has the following syntax:
std::atomic_ref<Type> ref(shared_var);
Parameters:
- Type: It is the type of the shared variable.
- shared_var: It is the shared variable to be accessed atomically.
Atomic Operations: Several atomic operations, including load, store, exchange, compare-and-exchange, fetch-add, fetch-sub, fetch-and, and fetch-or, are supported by std::atomic_ref.
Specializations for floating-point types
The std::atomic_ref supports extra atomic operations suitable for floating-point types, such fetch_add and fetch_sub, when instantiated with one of the cv-unqualified floating-point types (float, double, long double, and cv-unqualified extended floating-point types (since C++23)).
Even when an operation produces a result that cannot be represented in a floating-point type, no undefined behavior follows. The floating-point environment, in effect, may differ from the floating-point environment of the calling thread.
Example:
Let us take an example to illustrate the std::atomic_ref in C++.
std::atomic<int> shared_var{0};
std::atomic_ref<int> ref(shared_var);
int val = ref.load(); // Atomic load
ref.store(10); // Atomic store
int old_val = ref.exchange(20); // Atomic exchange
Memory Ordering:
The std::atomic_ref provides support for various memory ordering possibilities using the std::memory_order enumeration. These settings govern how software synchronizes atomic operations with other memory accesses. Typical ordering formats include the following:
std::memory_order_relaxed: The weakest ordering, std::memory_order_relaxed, permits optimizations that could rearrange memory accesses.
- std::memory_order_acquire: It ensures loads that come after an acquired operation experience the effects of stores that happened before the equivalent release action (std::memory_order_acquire).
- std::memory_order_release: It ensures that loads that follow the relevant acquire action can see stores that come before a release operation.
- std::memory_order_seq_cst: The strongest ordering, std::memory_order_seq_cst, ensures sequential consistency, which means that all threads view actions in the same order.
Syntax:
ref.store(10, std::memory_order_relaxed);
Example:
Let us take an example to illustrate the std::atomic_ref in C++.
#include <iostream>
#include <atomic>
int main() {
int shared_var = 0;
std::atomic_ref<int> ref(shared_var);
// Thread 1
ref.store(10);
// Thread 2
int val = ref.load();
std::cout << "Shared variable value: " << val << std::endl;
return 0;
}
Output:
![std::atomic_ref in C++](https://static.tutorialandexample.com/cpp/std-atomic-ref-in-cpp1.png)
Best Practices:
- When working with shared variables in multithreaded situations, it ensures the use of the std::atomic_ref function to avoid data races and maintain thread safety.
- Recognize the need for memory ordering and select the right memory order for atomic operations.
- When working with non-atomic types, use the std::atomic_ref instead of std::atomic to save extra overhead.
Conclusion:
In conclusion, std::atomic_ref is a useful C++ tool for concurrent program management of shared data. It prevents data races and ensures thread safety by granting atomic access to shared variables. By comprehending its use and implementing it into multithreaded programs, you can produce more dependable and durable code.