I want to use a Condvar
in my program. Below is a short test of it. I know it will be stuck forever on the loop.
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();
}
}
It doesn't compile:
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
I have looked at the example in the Rust documentation. The two differences I spot are:
Condvar
and Mutex
in a pair. This shouldn't matter, right? I want to create them separately.ref
keyword, which, if I understand this answer correctly, means that a reference to the lock is made. I figured that by changing the line to cvar.wait(&unlocked).unwrap();
would be the same thing, but then the compiler complains that a MutexGuard
, and not a reference, is expected.How can I make it compile?
The difference that you didn't spot is that wait
returns the MutexGuard
:
pub fn wait<'a, T>(
&self,
guard: MutexGuard<'a, T>
) -> LockResult<MutexGuard<'a, T>>
while !*started {
started = cvar.wait(started).unwrap();
}
wait
takes ownership of the MutexGuard
since it releases the lock and later reacquires it. Transferring ownership statically prevents using an improperly locked (or unlocked) variable, an example of using Rust's type system to the programmers advantage.
You need to do the same thing in your code:
let mut unlocked = var_in_lock.lock().unwrap();
loop {
unlocked = cvar.wait(unlocked).unwrap();
}
See also: