In modern C++, the concurrency support library is designed to solve problems in multi-thread operations. This library includes built-in support for threads (std::thread
), atomic operations (std::atomic
), mutual exclusion (std::mutex
), condition variables (std::condition_variable
), and many other features of a modern C++ compiler. In this post, we explain what is std::atomic
and how we can use atomic types efficiently in modern C++.
What is atomic (std::atomic) in modern C++?
In modern C++, the atomic library provides useful features for atomic operations allowing for lockless concurrent operations in C++. Every atomic operation is indivisible with regards to any other atomic operation that involves the same object.
C++11 adds atomic types and operations to the standard. Atomic types and operations provide a way of writing multi-threaded applications without using locks. In modern C++, the std::atomic<>
template class is defined in <atomic>
header and it can be used to wrap other types in order to do atomic operations on that type. When a thread writes to an atomic object another thread can read from it. Every instantiation and full specialization of the std::atomic
template defines an atomic type.
Atomic types ensure any read or write operation synchronizes as part of multi-thread operations, (i.e. using these types in std::thread
). They work well on private types (i.e. int
, float
, double
, etc.) or any type that is trivially copyable types which means it has at least one eligible copy constructor, move constructor, copy assignment operator, or move assignment operator and has non-deleted trivial destructor.
Here is a simple syntax for the atomic declaration:
1 2 3 |
atomic< type > type_name; |
Here are syntaxes defined in <atomic>
header since C++11:
1 2 3 |
template< class T > struct atomic; |
1 2 3 |
template< class T > struct atomic< T* >; |
Here are the syntaxes defined in the <memory>
header since C++20:
1 2 3 |
template< class T > struct atomic< std::shared_ptr<T> >; |
1 2 3 |
template< class T > struct atomic< std::weak_ptr<T> >; |
std::atomic
has many features to be used in atomic operations, i.e. load, store, operator=, wait, exchange, is_lock_free, etc. These will be explained in another post.
Is there a simple example of how to use std::atomic in modern C++?
Here is a simple std::atomic
example:
1 2 3 4 5 6 7 8 |
std::atomic<unsigned int> counter(0); // atomic type void myf() // a function to be used in multi-thread operations { counter++; // atomic operation } |
Is there a full example of how to use std::atomic with lambda in modern C++?
Here is a full std::atomic
example that uses std::thread
, and std::vector
:
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 |
#include <iostream> #include <vector> #include <thread> #include <atomic> std::atomic<unsigned int> counter = 0; int main() { std::vector< std::thread> myt; // vector for threads auto lambda = [&] { ++counter; }; for (unsigned int i = 0; i < 16; i++) { myt.push_back( std::thread( lambda) ); // add functions to thread vector } for (auto& t : myt) { t.join(); // wait each thread execution done and join back } std::cout << counter << std::endl; system("pause"); return 0; } |
Note that, every operation on these atomic types are called as atomic operation. For more information on this feature, see Atomic operations 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.