When is drop() called on Mutex?


#1

Why does the following code deadlock?

use std::sync::Mutex;

fn main() {
    let mutex = Mutex::new(());
    let mut guard = mutex.lock().unwrap();
    guard = mutex.lock().unwrap();
}

In my understanding, when you reassign guard, Rust calls drop() on the old MutexGuard value currently held in guard, which releases the lock, so the next mutex.lock().unwrap() shouldn’t block. But why does it still block?


#2

I just figured out the answer. The reason is that in the second

guard = mutex.lock().unwrap();

Rust calls mutex.lock() before calling drop() on guard. To fix the problem, call drop() on guard explicitly as the follows:

let mutex = Mutex::new(());
let mut guard = mutex.lock().unwrap();
drop(guard);
guard = mutex.lock().unwrap();

#3

They are dropped at the end of the scope, in the reverse order of creation: This is false for reassignment. See below.

let a = ...;
let b = ...;

//drop b
//drop a

You can also use smaller scopes to control the drop order:

{
    let a = ...;

    //drop a
}

{
    let b = ...;

    //drop b
}

#4

The question clearly was about when the old value is getting dropped during assignment – before evaluating the new value or after it.


#5

Yes, and the only thing I forgot about in my answer was the reassignment. I’m still pretty sure it’s dropped at the end of the scope, after the second guard has been dropped.


#6

I’m still pretty sure it’s dropped at the end of the scope, after the second guard has been dropped.

False. The old value of guard is dropped just before the new value is assigned to guard.


#7

Yeah, I just tested it. I was wrong when it comes to reassignments.

Note to self: read the question again, immediately before answering and don’t answer out of memory. Memory may be corrupt.


#8

Not if you’re written in safe Rust :wink:


#9

More likely something like Malbolge. :stuck_out_tongue_closed_eyes: I read somewhere that each time we remember something, the memory gets “replaced” with a memory of us remembering it. Don’t quote me on it, though. :wink: Anyway, this is off topic. Thank you both for pointing out my error. I’m just a neural network, after all.


#10

If guard were a dereference (not a local variable), then it’d have to drop after the assignment, because dropping before the assignment wouldn’t be panic-safe (the RHS might panic, and then you’ve got a dropped variable hanging out in memory. Oops.) I don’t think we guarantee the order of operations for local variable reassignment.