Synchronization Primitives • Mutexes & LocksMedium⏱️ ~2 min
Common Mutex Patterns and Pitfalls
Key Insight
Always pair lock with unlock. Think of them like parentheses: every open must have a close.
Common Pitfalls
Pitfall 1: Forget To Unlock
If you return early or throw an exception without unlocking, the mutex stays locked forever. All other threads block indefinitely.
Pitfall 2: Double Lock (Self-Deadlock)
You hold a lock and call a function that also tries to lock the same mutex. Unless you have a recursive mutex, deadlock. The thread waits for itself.
Solution: RAII (Resource Acquisition Is Initialization)
Use lock guards that automatically unlock when they go out of scope. In C++: std::lock_guard. In Java: try-with-resources or synchronized. In Python: with lock:.
{
std::lock_guard<std::mutex> g(m);
// work here
} // unlock automatic
std::lock_guard<std::mutex> g(m);
// work here
} // unlock automatic
Rule: Never call lock() and unlock() manually. Use RAII wrappers. They guarantee cleanup even on exceptions.
💡 Key Takeaways
✓Always pair lock with unlock. Early returns and exceptions can leave locks held forever.
✓Never block on another semaphore while holding a mutex. This is a common deadlock source.
✓Use RAII or try/finally to guarantee unlock even when exceptions occur.
✓Keep critical sections short. The longer you hold a lock, the more you block other threads.
✓Blocking inside a critical section is especially dangerous: it prevents progress and risks deadlock.
📌 Examples
1Java try/finally: lock.lock(); try { work(); } finally { lock.unlock(); }
2C++ RAII: std::lock_guard<std::mutex> guard(mutex); // automatically unlocks when guard goes out of scope