C++11 introduced a standard, portable threading library (<thread>, <mutex>, <atomic>, <future>), so concurrent code no longer needs to rely on platform-specific APIs.
#include <thread>
#include <mutex>
#include <atomic>
#include <future>
std::mutex mtx;
int sharedCounter = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx); // RAII: locks now, unlocks automatically
sharedCounter++;
}
std::atomic<int> atomicCounter{0}; // lock-free, thread-safe counter
int computeSquare(int x) {
return x * x;
}
int main() {
std::thread t1(increment);
std::thread t2(increment);
t1.join(); // wait for t1 to finish
t2.join();
std::future<int> result = std::async(computeSquare, 5); // runs asynchronously
std::cout << result.get() << "\n"; // blocks until the result is ready -> 25
return 0;
}
std::thread starts a new thread of execution running a given function; every thread must eventually be .join()ed (wait for it to finish) or explicitly .detach()ed (let it run independently), or the program terminates when the thread object is destroyed while still joinable.
Any data accessed from multiple threads simultaneously, where at least one thread writes, needs synchronization to avoid a data race (undefined behavior). std::mutex provides mutual exclusion — only one thread can hold the lock at a time — and std::lock_guard wraps it in RAII, automatically unlocking when the guard goes out of scope, even if an exception is thrown, exactly mirroring the RAII pattern used for memory and files. std::atomic<T> provides lock-free, thread-safe operations on simple types like counters, often faster than a mutex for very simple shared state.
std::async runs a function on a separate thread (or, depending on the implementation, potentially deferred until needed) and returns a std::future, a handle representing a result that will be ready later; calling .get() on it blocks until the result is available, giving a much simpler programming model than manually managing thread creation, a shared result variable, and synchronization by hand for a single computed value.