What is atomic in C++: Explanation and Usage
atomic refers to operations or variables that are performed as a single, indivisible step, preventing data races in multithreaded programs. The std::atomic template provides a way to safely share data between threads without using locks.How It Works
Imagine you have a shared notebook that multiple friends want to write in at the same time. If they write at the same time without coordination, the notes get mixed up and confusing. std::atomic in C++ acts like a special pen that ensures only one friend can write at a time, making each write appear instant and complete without interruption.
Technically, atomic operations are indivisible, meaning once started, they run to completion without being stopped or interfered with by other threads. This prevents problems called data races, where two threads try to change the same data simultaneously and cause unpredictable results.
The C++ standard library provides std::atomic types that wrap normal variables and guarantee these safe, atomic operations. This helps programmers write multithreaded code that is both safe and efficient without using heavy locks.
Example
This example shows how to use std::atomic to safely increment a counter from multiple threads without causing errors.
#include <iostream> #include <atomic> #include <thread> #include <vector> std::atomic<int> counter(0); void increment() { for (int i = 0; i < 1000; ++i) { ++counter; // atomic increment } } int main() { std::vector<std::thread> threads; for (int i = 0; i < 10; ++i) { threads.emplace_back(increment); } for (auto& t : threads) { t.join(); } std::cout << "Final counter value: " << counter.load() << std::endl; return 0; }
When to Use
Use std::atomic when you need to share simple data like counters, flags, or pointers between threads without using locks. It is ideal for cases where you want fast, low-overhead synchronization.
For example, atomic variables are useful in thread-safe counters, flags to signal events, or managing shared resources in concurrent programs. They help avoid complex locking mechanisms that can slow down your program or cause deadlocks.
However, for complex data or multiple related variables, you might still need locks or other synchronization methods.
Key Points
- Atomic operations are indivisible and prevent data races.
std::atomicprovides thread-safe variables without locks.- Atomic types are best for simple shared data like counters or flags.
- They improve performance by avoiding heavy locking.
- Use locks for complex data or multiple related variables.