如何在不移动 Mutex 变量的情况下使用 Condvar?

How do I use a Condvar without moving the Mutex variable?

我想在我的程序中使用 Condvar。下面是一个简短的测试。我知道它会永远卡在循环中。

use std::sync::{Arc, Condvar, Mutex};

fn main() {
    let var_in_lock = Arc::new(Mutex::new(8));
    let cvar = Arc::new(Condvar::new());

    let unlocked = var_in_lock.lock().unwrap();

    loop {
        cvar.wait(unlocked).unwrap();
    }
}

无法编译:

error[E0382]: use of moved value: `unlocked`
  --> src/main.rs:10:19
   |
7  |     let unlocked = var_in_lock.lock().unwrap();
   |         -------- move occurs because `unlocked` has type `std::sync::MutexGuard<'_, i32>`, which does not implement the `Copy` trait
...
10 |         cvar.wait(unlocked).unwrap();
   |                   ^^^^^^^^ value moved here, in previous iteration of loop

我查看了 Rust 文档中的 the example。我发现的两个区别是:

  1. 他们创造了一对 CondvarMutex。这应该无关紧要,对吧?我想单独创建它们。
  2. 它们使用 ref 关键字匹配锁,如果我理解 this 正确回答,这意味着对锁的引用。我认为通过将行更改为 cvar.wait(&unlocked).unwrap(); 将是同一件事,但随后编译器抱怨预期是 MutexGuard 而不是引用。

如何让它编译?

没有发现的区别在于wait returns MutexGuard:

pub fn wait<'a, T>(
    &self,
    guard: MutexGuard<'a, T>
) -> LockResult<MutexGuard<'a, T>>
while !*started {
    started = cvar.wait(started).unwrap();
}

wait 取得了 MutexGuard 的所有权,因为它释放了锁并稍后重新获得它。静态转移所有权可以防止使用不正确锁定(或解锁)的变量,这是使用 Rust 的类型系统对程序员有利的一个例子。


您需要在代码中做同样的事情:

let mut unlocked = var_in_lock.lock().unwrap();

loop {
    unlocked = cvar.wait(unlocked).unwrap();
}

另请参阅: