ReviseAlgo Logo

Concurrency

Deadlock Prevention

Identify Coffman deadlock conditions and resolve lock contention issues using std::scoped_lock.

Interview: Understanding Coffman conditions, locking order rules, and using std::scoped_lock for multi-mutex synchronization.

Last Updated: June 13, 2026 8 min read

A Deadlock occurs when two or more threads are blocked indefinitely, each waiting for a resource held by another. Understanding deadlock conditions and prevention strategies is critical for system reliability.

Coffman Conditions

A deadlock requires four conditions: Mutual Exclusion, Hold and Wait, No Preemption, and Circular Wait.

Lock ordering

Prevent deadlocks by ensuring all threads acquire shared locks in the same order.

std::scoped_lock

Introduced in C++17. A variadic lock manager that uses deadlock-avoidance algorithms to acquire multiple locks safely.

Resolving Deadlocks with std::scoped_lock

If Thread A locks Mutex 1 and waits for Mutex 2, while Thread B locks Mutex 2 and waits for Mutex 1, a deadlock occurs.

C++17's std::scoped_lock accepts multiple mutexes and locks them atomically without deadlocking, using algorithms that roll back acquisitions if contention is detected.

Code Walkthrough

Demonstrates a safe transfer operation between two objects using std::scoped_lock.

#include <iostream>
#include <mutex>
#include <thread>

class Account { public: std::mutex m_mutex; int m_balance;

Account(int bal) : m_balance(bal) {} };

void transfer(Account& from, Account& to, int amount) { // std::scoped_lock acquires locks for both accounts atomically without deadlocking std::scoped_lock lock(from.m_mutex, to.m_mutex);

if (from.m_balance >= amount) { from.m_balance -= amount; to.m_balance += amount; std::cout << "Transferred " << amount << " successfully.\n"; } }

int main() { Account a(100); Account b(50);

std::thread t1(transfer, std::ref(a), std::ref(b), 20); std::thread t2(transfer, std::ref(b), std::ref(a), 10);

t1.join(); t2.join(); return 0; }

Interview-Relevant Information

Q: What are the four Coffman conditions required for a deadlock?
Answer: 1. Mutual Exclusion: Resources can only be held by one thread at a time.
2. Hold and Wait: Threads holding resources can request additional ones.
3. No Preemption: Resources cannot be forcibly taken from a thread.
4. Circular Wait: A closed chain of threads exists where each waits for a resource held by the next.

Q: How does std::scoped_lock differ from std::lock?
Answer: std::lock is a function that locks multiple mutexes without deadlocking, but it does not manage lock lifetimes. You must still wrap the mutexes in std::unique_lock (using std::adopt_lock) to unlock them safely. std::scoped_lock is a C++17 RAII class template that locks mutexes on construction and unlocks them on destruction, making it the preferred approach.

Quick Checklist

Did you use std::scoped_lock when acquiring multiple locks? Do all threads lock resources in a consistent order? If yes, your locking logic is deadlock-free.

Use Cases

Acquiring database row locks on multiple records concurrently to perform bulk updates.

Synchronizing transfers between accounts or resources.

Common Mistakes

Acquiring locks in different orders across threads, which leads to circular wait deadlocks.

Nesting lock blocks manually instead of using std::scoped_lock to acquire multiple locks at once.