In C++11, the <atomic> header introduces a powerful mechanism for managing concurrent access to shared data in multithreaded applications. This header provides atomic types and operations that ensure safe access to variables, preventing data races and potential issues in multithreaded code. In this article, we'll explore the concept of <atomic> in C++11, along with proper examples and comments to illustrate its usage.
What is <atomic> in C++11?
In multithreaded programs, multiple threads often access and modify shared data simultaneously, which can lead to data races and unpredictable behavior. <atomic> solves this problem by providing atomic operations allowing threads to access and modify variables safely, without explicit locks or synchronization mechanisms.
In atomic operation, concurrent data access is regulated by a memory model for which the behavior is well-defined if one thread tries to access the data that another thread is currently accessing.
Syntax of Atomic Variable
std::atomic <type> var_name;
where,
- type: the type of variable that can be of any primitive data type such as int, bool, char, etc.
- var_name: name of the atomic variable.
Atomic Operations
Atomic operations are the operations that can be done on the std::atomic type and the <atomic> header provides some functions to perform these atomic operations.
S. No.
| Function
| Description |
---|
1
| load()
| This function loads the value stored in the atomic object. |
---|
2
| store()
| The function stores the value in the atomic object. |
---|
3
| exchange()
| This function replaces the value stored in the atomic object and returns the previously stored value. |
---|
4
| wait()
| This function is used to block the thread. |
---|
5
| notify_one()
| Notifies one of the threads that was waiting for the atomic object. |
---|
6
| notify_all()
| Notifies all the threads that were waiting for the atomic object. |
---|
7
| fetch_add()
| Gets the current value stored and adds the given value to the atomic object's value. |
---|
8
| fetch_sub()
| Gets the current value stored and subtracts the given value from the atomic object's value. |
---|
9
| fetch_and()
| Gets the current value stored and performs bitwise AND operation with atomic value and given value. |
---|
10
| fetch_or()
| Gets the current value stored and performs bitwise OR operation with atomic value and given value. |
---|
11
| fetch_xor()
| Gets the current value stored and performs bitwise XOR operation with atomic value and given value. |
---|
Examples of std::atomic
Let's explore some examples to understand how <atomic> works in practice.
Example 1
std::atomic can be used with various data types for atomic operations. Let's use it with integers:
C++
// C++ Program to illustrate the usage of <atomic> Header
#include <atomic>
#include <iostream>
#include <thread>
using namespace std;
atomic<int> counter(0); // Atomic integer
void increment_counter(int id)
{
for (int i = 0; i < 100000; ++i) {
// Increment counter atomically
counter.fetch_add(1);
}
}
int main()
{
thread t1(increment_counter, 1);
thread t2(increment_counter, 2);
t1.join();
t2.join();
cout << "Counter: " << counter.load() << std::endl;
return 0;
}
Output
Counter: 200000
Atomic Flag
A std::atomic_flag is a simple atomic boolean type that can be used as a lock-free flag. It is a specialization of atomic<bool> type that is guaranteed to be always lock-free.
It provides the following methods for atomic operations:
S. No.
| Method
| Description |
---|
1
| test()
| Gets the value stored in the atomic flag. |
---|
2
| test_and_set()
| Gets the value and sets the value of the flag. |
---|
3
| clear()
| Reset the value of the atomic flag. |
---|
Example 2: Atomic Flag
C++14
// C++ Program to illustrate the usage of <atomic> Header
#include <atomic>
#include <iostream>
#include <thread>
using namespace std;
// Initialize atomic flag
atomic_flag flag = ATOMIC_FLAG_INIT;
void thread_function(int id)
{
for (int i = 0; i < 5; ++i) {
while (flag.test_and_set(memory_order_acquire)) {
}
// Acquire lock
cout << "Thread " << id << " is running." << endl;
flag.clear(memory_order_release); // Release lock
}
}
// driver code
int main()
{
thread t1(thread_function, 1);
thread t2(thread_function, 2);
t1.join();
t2.join();
return 0;
}
Output
Thread 1 is running.
Thread 1 is running.
Thread 1 is running.
Thread 1 is running.
Thread 1 is running.
Thread 2 is running.
Thread 2 is running.
Thread 2 is running.
Thread 2 is running.
Thread 2 is running.
Explanation:
- We use std::atomic_flag as a lock to ensure that only one thread can enter the critical section at a time.
- test_and_set sets the flag to true (acquire lock) atomically, and clear resets it (release lock).
- The memory order parameters (std::memory_order_acquire and std::memory_order_release) ensure proper synchronization.
Related Articles
For a deeper understanding of <atomic>, you can refer to the following GeeksforGeeks articles:
Similar Reads
C++ 11 - <cfenv> Header
C++ 11 comes with new features and improvements and one of the main addition is the <cfenv> header that helps the programmers or developers with great control over the floating-point environment. It governs critical features of floating-point arithmetic like rounding modes and exceptions. <
4 min read
C++ 11 - <cstdint> Header
<cstdint> header in C++ ensures the portability of integer types with specialized width and signedness across various systems. The absence of standardization for integer types caused issues in coding and constructing portable programs before the advent of. In this article, we will explore the
3 min read
C++ 11 - <cinttypes> Header
The header offers type aliases and functions for manipulating integer types with particular sizes and signedness, as a part of the C++11 standard. Its aim is to present a standard group of integer types across diverse platforms and architectures. <cinttypes> header The <cinttypes> header
2 min read
C++17 - <charconv> Header
The C++ <charconv> header provides many functions for converting the character sequences to numerical values and vice-versa. It is considered better than the <cstdlib> header file functions for the same purpose. The functions provided by the <charconv> header file are generally fas
5 min read
C++23 - <expected> Header
C++23, the next major version of the C++ programming language, brings several exciting features and enhancements. One of the significant additions in C++23 is the <expected> header, which aims to improve error handling and make code more robust and readable. In this article, we will explore th
6 min read
C++ 20 - <latch> Header
In C++20, the header was introduced, which allows a synchronization primitive known as a latch. Latches allow one or more threads to wait until a certain number of operations have been finished before proceeding. A synchronization object called a latch is initialized with a preset count value. This
4 min read
C++23 <print> Header
C++ has long been a powerful language, known for its versatility and performance. With each new standard release, the language evolves, introducing features that enhance developer productivity and code readability. One of these additions of the C++ 23 standard is the introduction of <print> he
3 min read
C++ 20 - <numbers> Header
C++20 has a recently developed header file labeled that incorporates mathematical functions and constants. Its purpose is to provide standard library support for mathematical operations, simplifying the process for C++ programmers to incorporate mathematical functions and constants into their progra
3 min read
C++ 20 - <semaphore> Header
The C++20 <semaphore> header is part of the Concurrency Library Technical Specification (TS). Semaphores are synchronization primitives that help control access to shared resources in multi-threaded programs. The <semaphore> header provides the standard C++ way to work with semaphores. I
5 min read
C++ 20 - <stop_token> Header
C++20 has introduced the <stop_token> Header, presenting an alternative method for canceling asynchronous operations. A new class std::stop_token is provided by the <stop_token> header that allows for seamless communication of a termination request between two threads. In this article, w
4 min read