Though I have read all of the OP, the answer and the comments of Why do I get a deadlock when using Tokio with a std::sync::Mutex?, I don’t yet understand why the code in the OP blocks forever.
Here’s the slightly changed version of the original code:
use std::sync::Arc;
use std::sync::Mutex;
// use tokio::sync::Mutex;
use tokio::time::Duration;
async fn f(mtx: Arc<Mutex<i32>>, index: usize) {
println!("{}: trying to lock...", index);
{
let mut v = mtx.lock().unwrap();
// let mut v = mtx.lock().await;
println!("{}: locked", index);
tokio::time::sleep(Duration::from_millis(1)).await;
*v += 1;
}
println!("{}: unlocked", index);
}
#[tokio::main]
async fn main() {
let mtx = Arc::new(Mutex::new(0));
tokio::join!(f(mtx.clone(), 1), f(mtx.clone(), 2));
}
The output is
1: trying to lock...
1: locked
2: trying to lock...
(and blocks forever...)
According to the answer and the comments (and if I read them correctly), the reason is the entire code is executed in a single-threaded environment. If the italicized part is true, I can understand the blocking behavior. However, I don’t understand if the italicized part is actually true in the first place.
As far as I understand,
-
the default runtime of Tokio is multi-threaded unless you explicitly specify
#[tokio::main(flavor = "current_thread")]
(source) -
and
await
ed tasks can automatically be moved to another worker thread (source).
So I think the code does NOT block if they (i.e. f(mtx.clone(), 1).await
, f(mtx.clone(), 2).await
and sleep(...).await
) are chosen (by Tokio runtime) to be executed in different threads, but the code looks blocking as the runtime happens to choose they are all executed in the same single thread.
Is my understanding correct?