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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With