C++ · Advanced level

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

  1. Start two jthreads that print messages.
  2. Increment a shared counter from both and observe wrong totals.
  3. Run under ThreadSanitizer and read the race report.
  4. 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

  1. What is the advantage of std::jthread over std::thread?

    Show answer

    It joins automatically when destroyed.

  2. 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.