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
objectslock1
,lock2
,...
,lockn
using a deadlock avoidance algorithm to avoid deadlock.
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.