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
- Protect a shared results map with a mutex and scoped_lock.
- Measure how lock time affects the speed-up.
- Create a deadlock with two mutexes in opposite orders.
- 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
-
Why use std::scoped_lock rather than lock()/unlock()?
Show answer
It unlocks automatically, including when an exception is thrown.
-
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.