在防止死锁的同时,是否有一种工具可以在 Rust 中锁定多个互斥量?

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

在 Rust 中是否有类似 C++ std::lock() 的工具来防止代码中的死锁,如下所示:

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();
}

如果 foo 被线程 0 调用而 bar 被线程 1 调用,则有可能发生死锁。有什么东西,希望可变参数,因为我可以有超过 2 个,来帮助我解决这个问题,还是我自己验证锁定顺序的正确性?

来自 the documentation for std::lock:

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

如果 Mutex 是一个包含值的元组,这很容易解决,因此锁定元组会同时锁定两个值。

let tuple_mutex = Arc::new(Mutex::new((A, B)));

No, Rust 没有等同于 C++ 的函数 std::lock.

基于它似乎不在 std::sync documentation 中并且谷歌搜索没有提供任何有用信息的事实,我对这个断言非常有信心。

为什么不呢?好吧,如果我可以编辑一下,std::lock 并不像您希望的那样广泛有用。死锁避免是非常重要的,每个算法都会有可能导致性能不佳甚至活锁的极端情况。没有万能的死锁避免算法。¹(参见 Is std::lock() ill-defined, unimplementable, or useless?)在标准库中放置一个避免死锁的 lock 函数表明它是一个很好的 default 选择,并且可能鼓励使用它而不考虑其实现。大多数现实生活中的应用程序可能会使用更简单(且不太通用)的算法。

有些 crate 可以通过其他方式避免死锁。例如,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 有一个实验性的 deadlock_detection 功能(但我不确定它是如何工作的)。奇怪的是,我没有找到任何提供 C++ std::sort 等效于后退的板条箱。

无论如何,没有什么能阻止您编写自己的“后退”算法来解决这个问题;它只是不是标准库的一部分。


¹ 公平地说,您可以对 Rust 确实具有的其他函数进行相同的论证,例如 [T]::sort。但有许多应用程序排序不是瓶颈,任何相当快的算法都足够好。死锁避免通常不太可能是必需的,而且当它出现时更有可能对性能敏感。