Why is the Mutex lock held for the entire match statement?

So I was making a concurrent web crawler with BFS expansion to learn concurrency with Tokio in Rust, and for a part I needed to do this:

let queue: Arc<tokio::sync::Mutex<VecDeque<String>>> = Arc::clone(&queue);

let item = {
    let mut mutex_guard = queue.lock().await;
    mutex_guard.pop_front().await?
};

match item {
    Some(item) => todo!(),
    None => todo!(),
}

Note: This is a simplified implementation because the actual one is 500+ lines

This works fine, the lock is only held until the pop is done and other workers can also access it, but if I do this:

let queue: Arc<tokio::sync::Mutex<VecDeque<String>>> = Arc::clone(&queue);

match queue.lock().await.pop_front().await? {
    Some(item) => todo!(),
    None => todo!(),
}

It's locked until the worker finishes the call, and if the worker doesn't find any items in the queue, it waits until other workers finish in the actual implementation, so if there aren't any items in the queue at a given time, the program is deadlocked.

Why does this happen? Why doesn't the MutexGuard get dropped after the pop?

the reference says:

the drop scope of a temporary value is the end of the enclosing statement.

or, you can think of it like this: the temporary value is dropped at the semicolon.

2 Likes

Thanks! This does make sense to why scoping the lock to the initialization solved it, it made the statement end before the logic that waits even takes place, so the lock is dropped before waiting on new items, which would let other workers access the queue to add new items and make the program continue instead of deadlocking

To address a different kind of "why": Temporary drop scopes are determined syntactically, and there are use cases that require the syntactic pattern in question to keep temporaries alive until after the match in order to compile.

Imagine you had

    match some.chained().calls() {
        Enum::Var1(item) => println!("{item}"),
        Enum::Var2(item) => println!("{item}"),
    }

where a item is ultimately the borrow of some temporary introduced in the chain of calls.

1 Like