rustmutex

Is there a facility to lock multiple mutexes in Rust while preventing deadlocking?


Is there a C++ std::lock() like facility in Rust to prevent deadlocking in code like this:

type Type0 = Arc<Mutex<u8>>;
type Type1 = Arc<Mutex<u16>>;

fn foo(a: Type0, b: Type1) {
    let a_guard = a.lock().unwrap();
    let b_guard = b.lock().unwrap();
}

fn bar(a: Type0, b: Type1) {
    let b_guard = b.lock().unwrap();
    let a_guard = a.lock().unwrap();
}

If foo is called by thread-0 and bar by thread-1 there is a chance of deadlock. Is there something, hopefully variadic because I can have more than 2, to help me with this or am I all on my own verifying the correctness of order of locking?

From the documentation for std::lock:

Locks the given Lockable objects lock1, lock2, ..., lockn using a deadlock avoidance algorithm to avoid deadlock.


Solution

  • No, Rust does not have a function equivalent to C++'s std::lock.

    Based on the fact that it doesn't seem to be in the std::sync documentation and Googling brings up nothing useful, I'm pretty confident in this assertion.

    Why not? Well, if I may editorialize a bit, std::lock isn't as broadly useful as you might hope. Deadlock avoidance is nontrivial and every algorithm will have plausible corner cases that result in poor performance or even livelock. There is no one-size-fits-all deadlock avoidance algorithm.¹ (See Is std::lock() ill-defined, unimplementable, or useless?) Putting a deadlock-avoiding lock function in the standard library suggests that it's a good default choice, and perhaps encourages its use without regard for its implementation. Most real-life applications probably would do as well with a simpler (and less general-purpose) algorithm.

    There are crates that provide deadlock avoidance by other means. For instance, tracing-mutex provides locking types that create a dependency graph at runtime and will panic instead of deadlocking if the dependency graph contains a cycle. parking_lot has an experimental deadlock_detection feature (but I'm not sure how it works). Curiously, I didn't find any crates that provide a C++ std::sort equivalent with backing off.

    Anyway, nothing stops you writing your own "backing off" algorithm to solve this problem; it's just not part of the standard library.


    ¹ In fairness, you could make the same argument for other functions Rust does have, like [T]::sort. But there are many applications where sorting is not a bottleneck and any reasonably fast algorithm is good enough. Deadlock avoidance is both less likely to be necessary in general, and more likely to be performance-sensitive when it does appear.