-
-
Couldn't load subscription status.
- Fork 2.8k
Description
Version
└── tokio v1.44.2
└── tokio-macros v2.5.0 (proc-macro)
Platform
Linux beroal 6.14.3-arch1-1 #1 SMP PREEMPT_DYNAMIC Sun, 20 Apr 2025 12:38:52 +0000 x86_64 GNU/Linux
Description
Hi. When exploring whether Receiver can detect that the corresponding Senders are dropped, I found the following behavior demonstrated by the program below.
use std::error::Error;
use tokio::sync::watch;
fn new_watch<T: Clone>(initial: T)
-> Result<(watch::Sender<T>, watch::Receiver<T>), watch::error::SendError<T>> {
let (tx, rx) = watch::channel(initial.clone());
let () = tx.send(initial)?;
Ok((tx, rx))
}
async fn has_changed() -> Result<(), Box<dyn Error>> {
let (_tx, rx) = new_watch(()).map_err(Box::new)?;
rx.has_changed().map_err(Box::new)?;
Ok(())
}
async fn drop_sender_then_has_changed() -> Result<(), Box<dyn Error>> {
let rx = new_watch(()).map_err(Box::new)?.1;
rx.has_changed().map_err(Box::new)?;
Ok(())
}
async fn drop_sender_then_changed() -> Result<(), Box<dyn Error>> {
let mut rx = new_watch(()).map_err(Box::new)?.1;
rx.changed().await.map_err(Box::new)?;
Ok(())
}
#[tokio::main]
async fn main() {
eprintln!("has_changed: {:?}", has_changed().await);
eprintln!(
"drop_sender_then_has_changed: {:?}",
drop_sender_then_has_changed().await,
);
eprintln!(
"drop_sender_then_changed: {:?}",
drop_sender_then_changed().await,
);
}drop_sender_then_has_changed returns an error. The specification of watch::Receiver::has_changed says,
Returns an error if the channel has been closed.
However, not all receivers have been dropped. It's likely that the fact that all senders have been dropped is responsible for the error because my has_changed does not return an error.
The specification of watch::Receiver::changed says,
This method returns an error if and only if the
Senderis dropped.
All senders have been dropped, yet drop_sender_then_changed does not return an error.
Personally, I think that neither has_changed nor changed should return an error. If you allow for two Senders, why wouldn't you allow for zero Senders?
P.S. I suggest that you move the definition of “closed channel” to the top-level page instead of copying it to methods (such as watch::Sender::is_closed and watch::Sender::send).