Watch channel in rust

91 Views Asked by At

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.

1

There are 1 best solutions below

0
cafce25 On BEST ANSWER

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.