I'm not sure why it hangs on my.rw.write();.
If you uncomment the sleep call, it works fine. This means that the write access attempt is still blocking the main thread after the spawn thread has been executed and has released the RwLock. I think it must be fine in theory. Where am I wrong?
use std::sync::Arc;
use std::sync::RwLock;
use std::{thread, time};
struct MySt {
num1: i64,
num2: i64,
rw: RwLock<Vec<i64>>,
}
fn main() {
let my = Arc::new(MySt {
num1: 32,
num2: 64,
rw: RwLock::new(vec![1, 2, 3]),
});
let my2 = my.clone();
let t = thread::spawn(move || {
let mut rw = my2.rw.write().unwrap();
rw[0] = 5;
println!("child thread {}, {}, {}, {}", my2.num1, my2.num2, rw[0], rw[1]);
});
//thread::sleep(time::Duration::from_millis(1000));
let mut rw = my.rw.write().unwrap();
rw[1] = 6;
println!("main thread {}, {}, {}, {}", my.num1, my.num2, rw[0], rw[1]);
t.join().unwrap();
}
This is incorrect. Adding basic debugging output to differentiate them shows that the only
printlnthat runs is the one inmain.There's no guarantee which thread will execute first after the child thread is spawned. However, the main thread is likely to continue running since it's already running. If so it will lock the
RwLockviarwand hold the lock until the end of the function. However, before the end of the function, the main thread will block waiting for the child thread to join. The child thread cannot finish because it must acquire the write lock first. You have created a classic deadlock.To solve it, explicitly unlock the lock using
dropor add scopes to constrain the lock's lifetime:Adding the
sleepis likely to cause the child thread to execute first. It will then acquire the lock and exit, allowing the main thread to proceed.See also: