[2026] C++ Atomic Operations | Atomic Operations Guide

[2026] C++ Atomic Operations | Atomic Operations Guide

이 글의 핵심

C++ std::atomic and how to prevent data races in multithreads using atomic operations. Explains the advantages over mutexes and practical code patterns.

What is an atomic operation?

Atomic Operation is an indivisible operation, meaning that intermediate states are not observed. Prevents data races in multithreaded environments. 아래 코드는 cpp를 사용한 구현 예제입니다. 필요한 모듈을 import하고. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.

#include <atomic>
std::atomic<int> counter{0};
// atomic increment
counter++;  // thread safe
// non-atomic
int counter2 = 0;
counter2++;  // not thread safe

Why do you need it?:

  • Thread Safety: Prevent data races
  • Performance: Faster than mutex
  • Lock-Free: No deadlock
  • Synchronization: Guaranteed memory order```cpp // ❌ Non-atomic: race condition int counter = 0; void increment() { counter++; // 1. load, 2. add, 3. store (3 steps) } // Thread 1: load(0) -> add(1) -> store(1) // Thread 2: load(0) -> add(1) -> store(1) // Result: 1 (Expected: 2) // ✅ Atomic: Safe std::atomic counter{0}; void increment() { counter++; // Atomic (Level 1) } // Both Thread 1 and 2 safely increase // Result: 2
**How ​​atomic operations work**:
아래 코드는 mermaid를 사용한 구현 예제입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```mermaid
flowchart TD
A[Thread 1: counter++] --> B{atomic?}
B -->|Yes| C[hardware atomic instruction]
    B -->|No| D[1. load]
    D --> E[2. add]
    E --> F[3. store]
C --> G[complete]
F --> H{Intervention of Thread 2?}
H -->|Yes| I[race condition]
    H -->|No| G

Atomic operations vs mutex:

Featuresstd::atomicstd::mutex
PerformanceFastslow
ComplexityLow (simple operation)High (complex operations)
Lock-Free✅ Available❌ Not possible
Deadlock❌ None✅ Available
Use casesCounter, flagComplex data structure
// atomic: simple operation
std::atomic counter{0};
counter++;
// mutex: complex operation
std::mutex mtx;
std::map<int, int> data;
{
std::lock_guard lock(mtx);
data[key] = value;

}

## std::atomic

아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
```cpp
std::atomic<int> x{0};
std::atomic<bool> flag{false};
std::atomic<double> d{0.0};
// basic operations
x.store(10);
int value = x.load();
x.exchange(20);
```## Practical example
### Example 1: Counter
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <atomic>
#include <thread>
#include <vector>
std::atomic<int> counter{0};
void increment() {
    for (int i = 0; i < 1000; i++) {
counter++;  // atomic
    }
}
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 << counter << std::endl;  // 10000
}
```### Example 2: Flags
다음은 cpp를 활용한 상세한 구현 코드입니다. 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
std::atomic<bool> done{false};
// Thread 1
void worker() {
    // get the job done
    done.store(true);
}
// Thread 2
void monitor() {
    while (!done.load()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    std::cout << "Done" << std::endl;
}
```### Example 3: CAS (Compare-And-Swap)
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
std::atomic<int> value{0};
void update() {
    int expected = 0;
    int desired = 10;
    
// If expected == value, change to desired
    if (value.compare_exchange_strong(expected, desired)) {
std::cout << "success" << std::endl;
    } else {
std::cout << "Failure: " << expected << std::endl;
    }
}
```### Example 4: Lock-Free Stack
다음은 cpp를 활용한 상세한 구현 코드입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며, 에러 처리를 통해 안정성을 확보합니다, 반복문으로 데이터를 처리합니다, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
template<typename T>
class LockFreeStack {
    struct Node {
        T data;
        Node* next;
    };
    
    std::atomic<Node*> head{nullptr};
    
public:
    void push(T value) {
        Node* newNode = new Node{value, head.load()};
        
        while (!head.compare_exchange_weak(newNode->next, newNode)) {
            // retry
        }
    }
    
    bool pop(T& result) {
        Node* oldHead = head.load();
        
        while (oldHead && 
               !head.compare_exchange_weak(oldHead, oldHead->next)) {
            // retry
        }
        
        if (oldHead) {
            result = oldHead->data;
            delete oldHead;
            return true;
        }
        return false;
    }
};
```## atomic operations
다음은 cpp를 활용한 상세한 구현 코드입니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
std::atomic<int> x{0};
// read/write
x.store(10);
int value = x.load();
// exchange
int old = x.exchange(20);
// CAS
int expected = 10;
x.compare_exchange_strong(expected, 20);
// Arithmetic
x.fetch_add(5);
x.fetch_sub(3);
x++;
x--;
```## Frequently occurring problems
### Problem 1: Non-atomic operations
아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
```cpp
std::atomic<int> x{0};
// ❌ Non-atomic
x = x + 1;  // load + add + store (step 3)
// ✅ Atomic
x++;
x.fetch_add(1);
```### Issue 2: ABA Issues
아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
// A -> B -> A change not detected
std::atomic<Node*> head;
Node* oldHead = head.load();
// Another thread: A -> B -> A
head.compare_exchange_strong(oldHead, newNode);  // success (problem)
// ✅ Add version counter
struct Pointer {
    Node* ptr;
    size_t version;
};
std::atomic<Pointer> head;
```### Problem 3: Memory order
아래 코드는 cpp를 사용한 구현 예제입니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
```cpp
// ❌ relaxed (order not guaranteed)
data.store(42, std::memory_order_relaxed);
ready.store(true, std::memory_order_relaxed);
// ✅ acquire-release
data.store(42, std::memory_order_relaxed);
ready.store(true, std::memory_order_release);
```### Issue 4: Size limitations```cpp
// ✅ Check lock-free
std::atomic<int> x;
if (x.is_lock_free()) {
    std::cout << "Lock-free" << std::endl;
}
// Large types may not be lock-free
struct Large { int data[100]; };
std::atomic<Large> large;  // May not be lock-free
```## lock-free programming```cpp
// Pros: No locking, fast
// Cons: Complex, difficult to debug
// Use only in simple cases
std::atomic<int> counter;  // OK
// If it's complicated, it's a mutex
std::mutex mtx;
std::map<int, int> data;  // protected by mutex
```## Practice pattern
### Pattern 1: Spinlock
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 반복문으로 데이터를 처리합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <atomic>
#include <thread>
class SpinLock {
    std::atomic<bool> flag_{false};
    
public:
    void lock() {
        while (flag_.exchange(true, std::memory_order_acquire)) {
// spin
            std::this_thread::yield();
        }
    }
    
    void unlock() {
        flag_.store(false, std::memory_order_release);
    }
};
// use
SpinLock spinlock;
void criticalSection() {
    spinlock.lock();
// critical section
    spinlock.unlock();
}
```### Pattern 2: Singleton (Double-Checked Locking)
다음은 cpp를 활용한 상세한 구현 코드입니다. 필요한 모듈을 import하고, 클래스를 정의하여 데이터와 기능을 캡슐화하며, 조건문으로 분기 처리를 수행합니다. 각 부분의 역할을 이해하면서 코드를 살펴보시기 바랍니다.
```cpp
#include <atomic>
#include <mutex>
class Singleton {
    static std::atomic<Singleton*> instance_;
    static std::mutex mutex_;
    
    Singleton() = default;
    
public:
    static Singleton* getInstance() {
        Singleton* tmp = instance_.load(std::memory_order_acquire);
        
        if (tmp == nullptr) {
            std::lock_guard lock(mutex_);
            tmp = instance_.load(std::memory_order_relaxed);
            
            if (tmp == nullptr) {
                tmp = new Singleton();
                instance_.store(tmp, std::memory_order_release);
            }
        }
        
        return tmp;
    }
};
std::atomic<Singleton*> Singleton::instance_{nullptr};
std::mutex Singleton::mutex_;
```### Pattern 3: Task Queue```cpp
#include <atomic>
#include <queue>
#include <mutex>
template<typename T>
class WorkQueue {
    std::queue<T> queue_;
    std::mutex mutex_;
    std::atomic<size_t> size_{0};
    
public:
    void push(T item) {
        {
            std::lock_guard lock(mutex_);
            queue_.push(std::move(item));
        }
        size_.fetch_add(1, std::memory_order_release);
    }
    
    bool pop(T& item) {
        if (size_.load(std::memory_order_acquire) == 0) {
            return false;
        }
        
        std::lock_guard lock(mutex_);
        if (queue_.empty()) {
            return false;
        }
        
        item = std::move(queue_.front());
        queue_.pop();
        size_.fetch_sub(1, std::memory_order_release);
        return true;
    }
    
    size_t size() const {
        return size_.load(std::memory_order_acquire);
    }
};
```## FAQ
### Q1: When do you use atomic?
**A**: 
- **Counter**: Thread safe increment/decrement
- **Flag**: Share state between threads
- **Lock-Free Data Structure**: High-performance synchronization```cpp
std::atomic<int> counter{0};
std::atomic<bool> done{false};
```### Q2: What is the performance?
**A**: 
- **Lock-Free**: Faster than mutex
- **Complex Type**: Can be slow (uses lock)```cpp
// Check lock-free
std::atomic<int> x;
if (x.is_lock_free()) {
std::cout << "fast\n";
}
```### Q3: What is the memory order?
**A**: 
- **`relaxed`**: fast, no order guarantee
- **`acquire/release`**: general, order guaranteed
- **`seq_cst`**: safe, slow (default)```cpp
// relaxed: fast
x.store(42, std::memory_order_relaxed);
// acquire/release: general
x.store(42, std::memory_order_release);
int v = x.load(std::memory_order_acquire);
// seq_cst: safe (default)
x.store(42);
```### Q4: What is CAS?
**A**: **Compare-And-Swap**, which uses `compare_exchange`. This is the core of lock-free programming.
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
```cpp
std::atomic<int> value{0};
int expected = 0;
int desired = 10;
if (value.compare_exchange_strong(expected, desired)) {
std::cout << "Success\n";
}
```### Q5: What about ABA?
**A**: **The problem is that the change A → B → A cannot be detected**. Solved with **version counter**.
아래 코드는 cpp를 사용한 구현 예제입니다. 클래스를 정의하여 데이터와 기능을 캡슐화하며. 코드를 직접 실행해보면서 동작을 확인해보세요.
```cpp
struct Pointer {
    Node* ptr;
    size_t version;
};
std::atomic<Pointer> head;
```### Q6: What is the difference between atomic and volatile?
**A**: 
- **atomic**: thread-safe, atomic operations
- **volatile**: anti-optimization, not thread-safe.```cpp
// ❌ volatile: not thread safe
volatile int counter = 0;
counter++;  // race condition
// ✅ atomic: thread safe
std::atomic<int> counter{0};
counter++;  // atomic
```### Q7: Can all types be made atomic?
**A**: **Only small types are lock-free**. Large types can use locks internally.
아래 코드는 cpp를 사용한 구현 예제입니다. 조건문으로 분기 처리를 수행합니다. 코드를 직접 실행해보면서 동작을 확인해보세요.
```cpp
std::atomic<int> x;  // lock-free
std::atomic<std::string> s;  // May not be lock-free
// check
if (x.is_lock_free()) {
    std::cout << "Lock-free\n";
}
```### Q8: What are atomic learning resources?
**A**: 
- "C++ Concurrency in Action" by Anthony Williams
- "The Art of Multiprocessor Programming" by Maurice Herlihy
- [cppreference.com - Atomic](https://en.cppreference.com/w/cpp/atomic/atomic)
**Related article**: mutex, lock-free, [memory-order](/blog/cpp-memory-order/).
**One-line summary**: Atomic operations are indivisible operations, which prevent data races in a multithreaded environment.
---
## Good article to read together (internal link)

Here's another article related to this topic.
- [C++ Lock-Free Programming | "Lock Free Programming" Guide](/blog/cpp-lock-free-programming/)
- [C++ Memory Order | “Memory Order” Guide](/blog/cpp-memory-order/)
- [C++ Atomic | A complete guide to "Memory Order"](/blog/cpp-atomic-memory-order/)
## Practical tips

These are tips that can be applied right away in practice.
### Debugging tips
- If you run into a problem, check the compiler warnings first.
- Reproduce the problem with a simple test case
### Performance Tips
- Don't optimize without profiling
- Set measurable indicators first
### Code review tips
- Check in advance for areas that are frequently pointed out in code reviews.
- Follow your team's coding conventions
---
## Practical checklist

This is what you need to check when applying this concept in practice.
### Before writing code
- [ ] Is this technique the best way to solve the current problem?
- [ ] Can team members understand and maintain this code?
- [ ] Does it meet the performance requirements?
### Writing code
- [ ] Have you resolved all compiler warnings?
- [ ] Have you considered edge cases?
- [ ] Is error handling appropriate?
### When reviewing code
- [ ] Is the intent of the code clear?
- [ ] Are there enough test cases?
- [ ] Is it documented?
Use this checklist to reduce mistakes and improve code quality.
---
## Keywords covered in this article (related search terms)

This article will be helpful if you search for **C++**, **atomic**, **lock-free**, **C++11**, **concurrency**, etc.
---
## Related articles

- [C++ Lock-Free Programming | ](/blog/cpp-lock-free-programming/)
- [C++ Memory Order | ](/blog/cpp-memory-order/)
- [C++ Atomic | ](/blog/cpp-atomic-memory-order/)
- [C++ Lock-Free Programming Practice | CAS, ABA, memory order, high-performance queue [#34-3]](/blog/cpp-series-34-3-lock-free/)
- [C++ Lock-Free Programming Practice | CAS, ABA, memory order, high-performance queue [#51-5]](/blog/cpp-series-51-5-lock-free-programming/)
... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3