How do you handle concurrency in modern C++, and what causes a data race?
Since C++11 the standard library provides threading directly.
std::thread— a thread of execution. It must be joined or detached before destruction, or the program terminates.std::jthreadin C++20 joins automatically and supports cooperative cancellation.std::mutexwithstd::lock_guardorstd::unique_lock— RAII locking, so the mutex is released even if an exception propagates. Never calllock()andunlock()by hand.std::atomic— lock-free operations on single values, for counters and flags.std::condition_variable— for waiting until a condition holds. Always wait with a predicate, because spurious wakeups are permitted.std::asyncandstd::future— a higher-level way to get a result back from concurrent work.
A data race occurs when two threads access the same memory location concurrently, at least one writes, and there is no synchronisation between them. It is undefined behaviour, not merely a wrong value — the compiler is entitled to optimise on the assumption it cannot happen, so symptoms can be bizarre and unrelated.
How to avoid them: prefer immutable shared data or message passing over shared mutable state; protect what must be shared with a mutex; take locks in a consistent order to avoid deadlock; and run ThreadSanitizer in CI, because races are almost impossible to find by inspection.





