asynchronousrustwatchrust-tokio

Watch channel in rust


I need help in understanding borrow() and borrow_and_update() both looking similar to me.

#[tokio::main]
async fn main() {
    use tokio::sync::watch;
    use tokio::time::{Duration, sleep};

    let (tx, mut rx) = watch::channel("hello");
    let mut rx2 = tx.subscribe();
    tokio::spawn(async move {
        loop {
            println!("{}! ", *rx2.borrow_and_update());
            if rx.changed().await.is_err() {
                break;
            }
        }
    });

    sleep(Duration::from_millis(1000)).await;
    tx.send("world").unwrap();
    sleep(Duration::from_millis(1000)).await;
}

this is the example that I am using and I can't see any difference while using borrow() and borrow_and_update().
I have read the docs which say borrow_and_seen() will mark the value as seen while borrow doesn't.
can anyone help me understanding these two by giving a suitable example.


Solution

  • There is a dedicated section in the documentation on when to use which:

    borrow_and_update versus borrow

    If the receiver intends to await notifications from changed in a loop, Receiver::borrow_and_update() should be preferred over Receiver::borrow(). This avoids a potential race where a new value is sent between changed being ready and the value being read. (If Receiver::borrow() is used, the loop may run twice with the same value.)

    If the receiver is only interested in the current value, and does not intend to wait for changes, then Receiver::borrow() can be used. It may be more convenient to use borrow since it's an &self method—borrow_and_update requires &mut self.

    Giving an example that consistently reproduces the loop running twice is hard because it relies on consistently hitting the race condition.