Advanced level · Module 5: Concurrency in Modern C++ · Lesson 1 of 4
Threads and Data Races
Start threads with std::jthread and see how unsynchronised access to shared data produces data races.
In this lesson you will
- Start and join threads with std::jthread
- Recognise and detect data races
Key concepts
std::thread / std::jthreadjoindata raceThreadSanitizer
The lesson
A thread runs a function concurrently with the rest of the program. std::jthread (C++20) starts a thread and automatically joins it when destroyed, which avoids the crash caused by destroying an unjoined std::thread.
A data race happens when two threads access the same memory at the same time and at least one writes, without synchronisation. It is undefined behaviour: results may be wrong, inconsistent or appear correct during testing.
ThreadSanitizer (-fsanitize=thread) detects data races at run time and reports both conflicting accesses. Run concurrent code under it routinely.
Step by step
- Start two jthreads that print messages.
- Increment a shared counter from both and observe wrong totals.
- Run under ThreadSanitizer and read the race report.
- Fix it by giving each thread its own counter and summing afterwards.
Practice activity
Count readings in two halves of a data set on two threads without any shared mutable variable.
Expected result: The total is always correct and ThreadSanitizer reports no races.
Check your understanding
-
What is the advantage of std::jthread over std::thread?
Show answer
It joins automatically when destroyed.
-
When does a data race occur?
Show answer
When threads access the same data concurrently, at least one writes and there is no synchronisation.
Taught live by an instructor — online or in person. Free course lessons are for self-study and do not lead to a certificate — see registration options.