Correct Usage of Async with Tokio in Rust

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?)

3

1 Answer

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, and rr() cannot acquire a read lock until after the sleep.

Drop the lock before the sleep, and you'll see the expected output:

async fn ww(w: Arc<RwLock<MyThing>>) {
    loop {
        let mut write = w.write().await;
        (*write).n += 2;
        println!("Updated value: {}", (*write).n);
        drop(write);
        sleep(Duration::from_millis(200)).await;
    }
}
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Sarah Jenkins

Sarah Jenkins

Senior Technology Editor & AI Specialist

Sarah Jenkins is a veteran tech journalist with over 12 years of experience covering artificial intelligence, mobile innovations, and digital ethics. Her insights have appeared in leading technology publications worldwide.

Share this article
Twitter Facebook Pinterest