Courses/C++/Mutexes & Locks

    Lesson 26 • Advanced

    Mutexes, Locks & Deadlock Avoidance

    Protect shared data with mutex, lock_guard, unique_lock, scoped_lock, and learn deadlock prevention strategies.

    What You'll Learn

    • mutex and lock_guard for thread safety
    • unique_lock for flexible locking
    • Deadlock causes and prevention
    • scoped_lock for multi-mutex safety

    What is a Mutex?

    A mutex (mutual exclusion) is a lock that ensures only one thread can access a shared resource at a time. Think of it like a bathroom door lock — when one person locks it, everyone else waits until they're done.

    Lock TypeFlexibilityUse Case
    lock_guardLock once, auto-unlockSimple critical sections
    unique_lockLock/unlock/try/deferCondition vars, timed locks
    scoped_lockLock multiple mutexesDeadlock-free multi-lock

    Data Races & lock_guard

    See a data race in action and fix it with lock_guard

    Try it Yourself »
    C++
    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <vector>
    using namespace std;
    
    // Data race WITHOUT mutex
    void unsafeIncrement(int& counter, int iterations) {
        for (int i = 0; i < iterations; i++) {
            counter++;  // NOT thread-safe!
        }
    }
    
    // Thread-safe with lock_guard
    class SafeCounter {
        int count = 0;
        mutex mtx;
    public:
        void increment(int iterations) {
            for (int i = 0; i < iterations; i++) {
                lock_guard<mutex> lock(mtx);  // RAII lock
     
    ...

    unique_lock & Timed Locks

    Use flexible locking with defer, try_lock, and timed_mutex

    Try it Yourself »
    C++
    #include <iostream>
    #include <thread>
    #include <mutex>
    #include <chrono>
    using namespace std;
    
    mutex mtx;
    
    // unique_lock — more flexible than lock_guard
    void flexibleLocking() {
        // Deferred locking
        unique_lock<mutex> lock(mtx, defer_lock);
        
        cout << "Doing work without lock..." << endl;
        this_thread::sleep_for(chrono::milliseconds(10));
        
        // Lock when needed
        lock.lock();
        cout << "Critical section (locked)" << endl;
        lock.unlock();
        
        cout << "More work 
    ...

    Deadlock Prevention

    Avoid deadlocks with std::lock and scoped_lock

    Try it Yourself »
    C++
    #include <iostream>
    #include <thread>
    #include <mutex>
    using namespace std;
    
    mutex mutexA, mutexB;
    
    // DEADLOCK EXAMPLE (DO NOT USE!)
    // void deadlockThread1() {
    //     lock_guard<mutex> lockA(mutexA);
    //     this_thread::sleep_for(chrono::milliseconds(10));
    //     lock_guard<mutex> lockB(mutexB);  // Waits for B
    // }
    // void deadlockThread2() {
    //     lock_guard<mutex> lockB(mutexB);
    //     this_thread::sleep_for(chrono::milliseconds(10));
    //     lock_guard<mutex> lockA(mutexA);  // Waits for A
    ...

    Common Mistakes

    ⚠️ Locking order: If thread 1 locks A then B, and thread 2 locks B then A — deadlock. Always use scoped_lock for multiple mutexes.

    ⚠️ Holding locks too long: Don't do I/O, network calls, or heavy computation while holding a lock. Lock only the critical section.

    ⚠️ Recursive locking: Locking the same mutex twice in one thread deadlocks. Use recursive_mutex if you must (but redesign first).

    Pro Tips

    💡 Minimise critical sections: Lock, do the minimum work, unlock. Prepare data outside the lock.

    💡 Use scoped_lock (C++17): It replaces lock() + lock_guard(adopt_lock) with a single clean statement.

    💡 Consider lock-free: For simple counters, std::atomic is faster than mutex. We'll cover this next.

    📋 Quick Reference

    OperationSyntax
    RAII locklock_guard<mutex> lock(m);
    Flexible lockunique_lock<mutex> lock(m);
    Multi-lockscoped_lock lock(m1, m2);
    Try lockunique_lock lock(m, try_to_lock);
    Deferred lockunique_lock lock(m, defer_lock);

    Lesson Complete!

    You now know how to protect shared data with mutexes and prevent deadlocks. Next: Atomic Operations — lock-free synchronisation for maximum performance.

    Sign up for free to track which lessons you've completed and get learning reminders.

    Previous

    Cookie & Privacy Settings

    We use cookies to improve your experience, analyze traffic, and show personalized ads. You can manage your preferences below.

    By clicking "Accept All", you consent to our use of cookies for analytics and personalized advertising. You can customize your preferences or reject non-essential cookies.

    Privacy PolicyTerms of Service