Lesson content
Read, practise, then check your understanding
std::thread starts a thread of execution. A joinable thread must be joined or detached before its destructor, otherwise the program terminates. std::jthread joins automatically and supports cooperative stopping.
#include <mutex>
#include <thread>
int total{};
std::mutex totalMutex;
void add(int value) {
std::scoped_lock lock{totalMutex};
total += value;
}
int main() {
std::jthread first{add, 3};
std::jthread second{add, 4};
}
A data race occurs when threads access the same memory concurrently, at least one access writes, and no synchronization orders them. It is undefined behavior. std::mutex plus std::lock_guard, std::unique_lock, or std::scoped_lock protects invariants. Keep critical sections small and establish a consistent lock order to prevent deadlock.
Communication choices
Atomics safely coordinate simple independent values, but correct memory ordering is subtle; use default sequential consistency until measurement and proof justify weaker ordering. Condition variables let threads sleep until a predicate may be true and must be checked in a loop because wakeups can be spurious.
std::async and futures communicate a result or exception. Exceptions do not automatically cross thread boundaries; capture them through futures or std::exception_ptr. Prefer immutable data, ownership transfer, message passing, and task-level concurrency over widespread shared mutable state. Test with stress, sanitizers where available, and explicit shutdown behavior.
Knowledge check
Answer every question correctly to complete this chapter.
0 of 10 checks passed
Your progress is saved on this device.