C++ Concurrency Core Concepts: Processes, Threads, and Memory Model

August 14, 2025

In this post I will explain the fundamentals of concurrency in C++: processes vs threads, memory models & synchronization, and the C++ memory model. I’ll also provide example code you can try.

Processes vs Threads

Memory Models & Synchronization

The C++ Memory Model

Example Code

Example 1: Race Condition

#include <iostream>
#include <thread>

int counter = 0;

void increment() {
    for (int i = 0; i < 1000000; i++)
        counter++;
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter = " << counter << "\n";
}

Example 2: Fix with std::mutex

#include <iostream>
#include <thread>
#include <mutex>

int counter = 0;
std::mutex mtx;

void increment() {
    for (int i = 0; i < 1000000; i++) {
        std::lock_guard<std::mutex> lock(mtx);
        counter++;
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter = " << counter << "\n";
}

Example 3: Use std::atomic

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> counter(0);

void increment() {
    for (int i = 0; i < 1000000; i++)
        counter++;
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    std::cout << "Final counter = " << counter << "\n";
}

Example 4: Relaxed Memory Order

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> flag(0);
std::atomic<int> data(0);

void writer() {
    data.store(42, std::memory_order_relaxed);
    flag.store(1, std::memory_order_relaxed);
}

void reader() {
    while (flag.load(std::memory_order_relaxed) == 0) {
        // spin
    }
    std::cout << "Reader sees data = " << data.load(std::memory_order_relaxed) << "\n";
}

int main() {
    std::thread t1(writer);
    std::thread t2(reader);

    t1.join();
    t2.join();
}

Example 5: Acquire–Release Fix

#include <iostream>
#include <thread>
#include <atomic>

std::atomic<int> flag(0);
std::atomic<int> data(0);

void writer() {
    data.store(42, std::memory_order_relaxed);
    flag.store(1, std::memory_order_release); // release
}

void reader() {
    while (flag.load(std::memory_order_acquire) == 0) { // acquire
        // spin
    }
    std::cout << "Reader sees data = " << data.load(std::memory_order_relaxed) << "\n";
}

int main() {
    std::thread t1(writer);
    std::thread t2(reader);

    t1.join();
    t2.join();
}

Takeaways

← Back to blog