Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this MutexGuard not dropped?

Tags:

rust

lifetime

In Chapter 20 of The Rust Book, an example implementation of a thread pool is built. Jobs are passed to workers via a single-producer multiple-consumer channel: each worker has an Arc<Mutex<Receiver>> to pick jobs off the queue.

The first example of the worker thread body looks like this:

loop {
    let job = receiver.lock().unwrap().recv().unwrap();

    println!("Worker {} got a job; executing.", id);

    job();
}

When I saw this my first thought was "but the mutex is held while job is run" (i.e. I did not expect the mutex to be released until the return value of lock went out of scope at the end of the loop).

However the book then provides a second example:

while let Ok(job) = receiver.lock().unwrap().recv() {
    println!("Worker {} got a job; executing.", id);

    job();
}

The book says that this example exhibits the problem I described, i.e. "the lock remains held for the duration of the call to job()". It goes on to say that the former example escapes the issue because "the MutexGuard returned from the lock method is dropped as soon as the let job statement ends".

That last part makes it sound as if, because the MutexGuard is never actually assigned to a variable, its lifetime ends as soon as the expression is finished evaluating. That would make sense. But isn't that also true of the second example? Why does being in a while expression change the lifetime of the MutexGuard value?

like image 444
Brendan Avatar asked Nov 21 '19 06:11

Brendan


2 Answers

Michael's answer is basically correct. More details can be found in Rust's reference regarding Place Expressions, Value Expressions and Temporary Lifetimes:

In the first example (let job = ...), the MutexGuard is a temporary. The temporary lifetime ends at the end of the statement. Therefore the MutexGuard is dropped after the let job = ... statement.

In the second example while let ..., the MutexGuard is part of the scrutinee of the while-expression. This makes the MutexGuard part of a value-expression in a place-expression context. Since promotion to a 'static can't occur, the lifetime of the entire scrutinee is the enclosing block, not the enclosing statement. That is, the MutexGuard is held for the whole while let-block.

like image 181
user2722968 Avatar answered Nov 10 '22 12:11

user2722968


The temporaries are cleaned up at the end of the statement, not the end of the expression.

In this case the whole while block is the statement, not just the expression inside the let pattern matching.

like image 22
Michael Anderson Avatar answered Nov 10 '22 12:11

Michael Anderson