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 调用,则可能会出现死锁。有什么东西(希望是可变的,因为我可以有两个以上)来帮助我解决这个问题,还是我自己验证锁定顺序的正确性?
std::lock
的文档:
使用死锁避免算法锁定给定的
对象Lockable
、lock1
、lock2
、...
以避免死锁。lockn
不,Rust 没有相当于 C++ 的功能
std::lock
。
std::sync
文档中并且谷歌搜索没有带来任何有用的结果,我对这个断言非常有信心。
为什么不呢?好吧,如果我可以稍微编辑一下,
std::lock
并不像您希望的那样广泛有用。避免死锁并非易事,每种算法都会有可能导致性能不佳甚至活锁的极端情况。不存在万能的死锁避免算法。(参见 std::lock() 是否定义不明确、无法实现或无用?)建议在标准库中放置一个避免死锁的 lock
函数这是一个很好的“默认”选择,并且可能鼓励使用它而不考虑其实现。大多数现实生活中的应用程序可能会使用更简单(且不太通用)的算法。
有些板条箱可以通过其他方式避免死锁。例如,tracing-mutex提供了在运行时创建依赖图的锁定类型,如果依赖图包含循环,则会出现恐慌而不是死锁。 parking_lot 有一个实验性的 deadlock_detection
功能(但我不确定它是如何工作的)。奇怪的是,我没有找到任何提供 C++
std::sort
等价的板条箱。无论如何,没有什么可以阻止你编写自己的“后退”算法来解决这个问题;它只是不是标准库的一部分。
¹ 公平地说,您可以对 Rust 具有的其他功能进行相同的论证,例如[T]::sort
。但在许多应用中,排序不是瓶颈,任何相当快的算法就足够了。一般来说,避免死锁不太可能是必要的,而且当它确实出现时,它更有可能对性能敏感。
Mutex
是一个包含值的元组,那么锁定该元组会同时锁定两个值。
let tuple_mutex = Arc::new(Mutex::new((A, B)));
Arc<Mutex<User>>
我编写了一个实用函数来处理它:
async fn ordered_lock<'a, T>(
m1: &'a Arc<Mutex<T>>,
m2: &'a Arc<Mutex<T>>,
) -> (MutexGuard<'a, T>, MutexGuard<'a, T>) {
let l1;
let l2;
if Arc::as_ptr(m1) > Arc::as_ptr(m2) {
l2 = m2.lock().await;
l1 = m1.lock().await;
} else {
l1 = m1.lock().await;
l2 = m2.lock().await;
};
(l1, l2)
}
它与非异步互斥体的工作原理相同,