Mutex Lock

Mutex-Lock Release Pattern

A release pattern ensures a mutex lock is always released regardless of how control leaves the critical section. A plain acquire() / release() pair is unsafe because exceptions, early return, or break can skip the release and strand the lock forever. Two patterns fix this: a _Finally clause that always runs, or RAII where the destructor releases the lock.

Why not just be careful with release?

Because “careful” does not survive real code. Exception-throwing calls inside the critical section, refactors that add an early return, or nested conditionals make it easy to miss a release path. The fix is to bind release to a mechanism the compiler enforces: exception unwinding (_Finally) or block exit (RAII destructor).

_Finally pattern (exception-safe)

uOwnerLock lock;
lock.acquire();
try {
    // protected by lock
} _Finally {
    lock.release();            // runs on normal exit, return, break, exception
}

The _Finally block is guaranteed to run on every exit path out of the try, including uncaught exceptions passing through.

RAII pattern (preferred in C++)

class RAII {
    uOwnerLock & lock;
public:
    RAII( uOwnerLock & lock ) : lock( lock ) { lock.acquire(); }
    ~RAII() { lock.release(); }
};
 
uOwnerLock lock;
{
    RAII raii( lock );         // acquired by constructor
    // protected by lock
}                              // released by destructor at block exit

The destructor fires on normal scope exit, on return, on break out of the enclosing loop, and on stack unwind from an exception. Same guarantee as _Finally, but idiomatic C++ and composable with other scoped resources.

Cannot prevent barging

Neither pattern can be used for barging prevention. Prevention requires holding the lock across the hand-off from releaser to a specific woken task, so the user code never controls the release instant. A RAII destructor always releases at block exit, which is the wrong moment when you want the scheduler to atomically pass the lock to a particular waiter.