I never worked with asynchronous code (but have exp with multithreading) in Rust. I thought it is mostly the same thing, however I got some problems. Here listing of my sample:
use tokio::{join, sync::RwLock};
use std::sync::Arc;
use tokio::time::{sleep, Duration};
struct MyThing {
n: usize,
}
impl MyThing {
fn new(x: usize) -> MyThing {
MyThing{ n: x }
}
}
async fn rr(v: Arc<RwLock<MyThing>>) {
loop {
let read = v.read().await;
println!("Value : {}", (*read).n);
// sleep(Duration::from_millis(50)).await;
}
}
async fn ww(w: Arc<RwLock<MyThing>>) {
loop {
let mut write = w.write().await;
(*write).n += 2;
println!("Updated value: {}", (*write).n);
sleep(Duration::from_millis(200)).await;
}
}
#[tokio::main]
async fn main() {
let x = Arc::new(RwLock::new(MyThing::new(11)));
let w = x.clone();
let r = x.clone();
let h = tokio::spawn(async move {
ww(w).await
});
let j = tokio::spawn(async move {
rr(r).await
});
join!(h);
join!(j);
}
So i was expecting that I would get 2 async "threads", and while ww
is sleeping I will get ton of readings, but, im getting next output:
Updated value: 13
Value : 13
Updated value: 15
Value : 15
Updated value: 17
Value : 17
Updated value: 19
Value : 19
Updated value: 21
...
So my question is: Is it correct behavior or I just dumb?
(And additional question, if i delete await
in tokio::spawn
after i call function, those functions rr
and ww
aren't called?)
You're sleeping while holding the lock. This bug can be caused in threaded programming too.
Because you don't drop the lock (
write
), it is not released, andrr()
cannot acquire a read lock until after the sleep.Drop the lock before the sleep, and you'll see the expected output: