Deadlock occurs when threads wait on one another in a cycle, so none can make progress. A common case involves two mutexes: each thread holds one and waits to acquire the other. Unlike a race condition, the threads are not competing to act first; both are stuck waiting. section 3.2.4 section 3.2.3
Swapping two protected objects
Suppose each object has its own mutex, and swapping their data requires both locks. Locking the first argument before the second is not a consistent order: another thread can call the same swap with the arguments reversed. Each thread may then acquire a different mutex and wait forever for the other. section 3.2.4
Listing 3.6. Using std::lock() and std::lock_guard in a swap operation
class some_big_object;
void swap(some_big_object& lhs,some_big_object& rhs);
class X
{
private:
some_big_object some_detail;
std::mutex m;
public:
X(some_big_object const& sd):some_detail(sd){}
friend void swap(X& lhs, X& rhs)
{
if(&lhs==&rhs)
return;
std::lock(lhs.m,rhs.m); #1
std::lock_guard<std::mutex> lock_a(lhs.m,std::adopt_lock); #2
std::lock_guard<std::mutex> lock_b(rhs.m,std::adopt_lock); #3
swap(lhs.some_detail,rhs.some_detail);
}
};
!@%STYLE%@!
{"css":"{\"css\": \"font-weight: bold;\"}","target":"[[{\"line\":13,\"ch\":68},{\"line\":13,\"ch\":70}],[{\"line\":14,\"ch\":68},{\"line\":14,\"ch\":70}],[{\"line\":15,\"ch\":68},{\"line\":15,\"ch\":70}]]"}
!@%STYLE%@!
The swap checks for the same object first, acquires both mutexes with std::lock, then gives each acquired lock to a std::lock_guard using std::adopt_lock before changing the data. section 3.2.4
When an operation needs multiple mutexes, std::lock acquires them together without deadlock during that acquisition. std::scoped_lock offers a shorter form for the swap. If locks must instead be acquired separately, use a fixed order that remains the same across callers—not an order based merely on argument position. section 3.2.4 section 3.2.5
Other ways to break or avoid a waiting cycle:
- Avoid acquiring a lock while holding another when possible. Do not call user-supplied code under a lock without considering whether it might acquire one. section 3.2.5
- Enforce an order when separate acquisitions are unavoidable. A hierarchical mutex can check lock levels and throw on an order violation. section 3.2.5
- Look beyond mutexes: two threads that each join the other also deadlock, and a waiting cycle can involve more than two threads. section 3.2.5
A deadlocked task may never finish; if it serves the user interface, the interface may stop responding. Do not confuse this with livelock: livelocked threads keep running and checking, often consuming CPU, while still failing to make progress. section 11.1.1














