Mutex Lock

Trylock

try_lock is a non-blocking variant of lock(): it attempts to acquire the mutex and returns immediately with a success/failure flag instead of parking the thread. Common in Rust, C++ (std::mutex::try_lock), POSIX (pthread_mutex_trylock), and Java (ReentrantLock.tryLock).

Why use it?

A blocking lock() forces a context switch if the lock is contended, which is exactly what kicks off a lock convoy. try_lock lets the caller decide what to do on failure: yield, back off, skip the work, or escalate to a blocking acquire.

Uses:

  • Breaking deadlock hold-and-wait. If a thread already holds lock A and needs B, calling try_lock(B) and releasing A on failure breaks the hold-and-wait Coffman condition
  • Avoiding lock convoys. Retry a bounded number of times with thread::yield_now() between attempts, then fall back to lock(). Even a retry limit of 2 lets threads recover without convoy formation
  • Opportunistic work. “If I can grab the lock right now, do the thing; otherwise skip it.” Useful for best-effort caching, metrics updates, non-critical cleanup

Rust retry-then-fallback pattern (from ECE459 L12):

let mut retries = 0;
let retries_limit = 10;
let counter = Mutex::new(0);
loop {
    if retries < retries_limit {
        let mut l = counter.try_lock();
        if l.is_ok() { *l.unwrap() = 1; break; }
        else { retries += 1; thread::yield_now(); }
    } else { *counter.lock().unwrap() = 1; break; }
}

Spurious failures

POSIX pthread_mutex_trylock and some implementations are allowed to fail even when the lock is available (e.g. under contention on the internal state). Treat failure as “try again later,” not “definitely held by someone else.”