C++ · Advanced level

Advanced level · Module 5: Concurrency in Modern C++ · Lesson 2 of 4

Mutexes, Locks and Deadlocks

Protect shared data with mutexes and RAII locks, and avoid deadlocks.

In this lesson you will

  • Use std::mutex with std::scoped_lock
  • Avoid deadlocks through lock ordering and minimal locking

Key concepts

std::mutexstd::lock_guard / std::scoped_lockcritical sectiondeadlock

The lesson

A mutex lets only one thread at a time run a critical section. Never call lock and unlock by hand; use std::scoped_lock lock{m};, which locks in its constructor and unlocks in its destructor, even if an exception is thrown.

Keep critical sections short: copy or prepare data outside the lock and hold it only while touching shared state. Long locks remove the benefit of using threads.

A deadlock occurs when threads wait for each other's locks forever. Avoid it by always taking locks in the same order, or by locking several mutexes at once with std::scoped_lock{m1, m2}, which avoids deadlock.

Step by step

  1. Protect a shared results map with a mutex and scoped_lock.
  2. Measure how lock time affects the speed-up.
  3. Create a deadlock with two mutexes in opposite orders.
  4. Fix it with std::scoped_lock on both.

Practice activity

Add a thread-safe progress counter and results store to the parallel processor.

Expected result: Results are correct, ThreadSanitizer is clean and the program never hangs.

Check your understanding

  1. Why use std::scoped_lock rather than lock()/unlock()?

    Show answer

    It unlocks automatically, including when an exception is thrown.

  2. How can a deadlock between two mutexes be avoided?

    Show answer

    Always lock them in the same order, or lock both together with std::scoped_lock.

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.