Search code examples
rustmutexdeadlock

Why is this value not dropped after last use?


The following code deadlocks because the mutex is not unlocked after the last use of 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();
}

The fix is to uncomment the explicit drop(v). Why does compiler not automatically drop v after its last use?

In contrast, the Rust compiler knows to correctly drop v early in the following case:

fn main() {
    let mut a = 3;
    let v = &mut a;
    *v += 1;
    println!("v is {v}");
    let w = &mut a;
    *w += 1;
    println!("w is {w}");
}

This behavior seems natural, I would expect the compiler to do the same above.


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?