The following code deadlocks due to mutex not being released after the last use of v
. The fix is to uncomment the explicit drop(v)
.
use std::sync::{Arc,Mutex};
fn main() {
let a = Arc::new(Mutex::new(3));
let mut v = a.lock().unwrap();
*v += 1;
println!("v is {v}");
// drop(v);
let b = Arc::clone(&a);
std::thread::spawn(move || {
let mut w = b.lock().unwrap();
*w += 1;
println!("w is {w}");
}).join().unwrap();
}
Why does compiler not automatically drop v
after it’s last used?
In contrast, rust compiler knows to correctly drop v
early in the following case,
fn main() {
let mut a = 3;
let v = &mut a;
*v += 1;
let w = &mut a;
*w += 1;
println!("{w}");
}
This behavior seems natural, I would expect the compiler to do the same with Arc<Mutex<..>>.
>Solution :
Values are dropped when their scope ends, not after their last use. What may be confusing you is that the borrow checker knows references are inconsequential after their last use, and thus considers their lifetimes differently for the purposes of enforcing Rust’s referential guarantees.
Technically v
in the second example is not dropped until the end of the scope either, but there is no drop logic for references. See What are non-lexical lifetimes?