From 0f3c7d18fb1213ad285173210820924b76b534a1 Mon Sep 17 00:00:00 2001 From: Ivan Tham Date: Tue, 22 Dec 2020 02:16:01 +0800 Subject: [PATCH] Explain non-dropped sender recv in docs Original senders that are still hanging around could cause Receiver::recv to not block since this is a potential footgun for beginners, clarify more on this in the docs for readers to be aware about it. Fix minor tidbits in sender recv doc Co-authored-by: Dylan DPC Add example for unbounded receive loops in doc Show the drop(tx) pattern, based on tokio docs https://tokio-rs.github.io/tokio/doc/tokio/sync/index.html Fix example code for drop sender recv Fix wording in sender docs Co-authored-by: Josh Triplett --- library/std/src/sync/mpsc/mod.rs | 53 +++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index db0777ee9f0..0465a19a478 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -105,6 +105,35 @@ //! }); //! rx.recv().unwrap(); //! ``` +//! +//! Unbounded receive loop: +//! +//! ``` +//! use std::sync::mpsc::sync_channel; +//! use std::thread; +//! +//! let (tx, rx) = sync_channel(3); +//! +//! for _ in 0..3 { +//! // It would be the same without thread and clone here +//! // since there will still be one `tx` left. +//! let tx = tx.clone(); +//! // cloned tx dropped within thread +//! thread::spawn(move || tx.send("ok").unwrap()); +//! } +//! +//! // Drop the last sender to stop `rx` waiting for message. +//! // The program will not complete if we comment this out. +//! // **All** `tx` needs to be dropped for `rx` to have `Err`. +//! drop(tx); +//! +//! // Unbounded receiver waiting for all senders to complete. +//! while let Ok(msg) = rx.recv() { +//! println!("{}", msg); +//! } +//! +//! println!("completed"); +//! ``` #![stable(feature = "rust1", since = "1.0.0")] @@ -436,6 +465,9 @@ pub struct IntoIter { /// /// Messages can be sent through this channel with [`send`]. /// +/// Note: all senders (the original and the clones) need to be dropped for the receiver +/// to stop blocking to receive messages with [`Receiver::recv`]. +/// /// [`send`]: Sender::send /// /// # Examples @@ -642,7 +674,7 @@ impl UnsafeFlavor for Receiver { /// the same order as it was sent, and no [`send`] will block the calling thread /// (this channel has an "infinite buffer", unlike [`sync_channel`], which will /// block after its buffer limit is reached). [`recv`] will block until a message -/// is available. +/// is available while there is at least one [`Sender`] alive (including clones). /// /// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but /// only one [`Receiver`] is supported. @@ -805,6 +837,11 @@ impl Sender { #[stable(feature = "rust1", since = "1.0.0")] impl Clone for Sender { + /// Clone a sender to send to other threads. + /// + /// Note, be aware of the lifetime of the sender because all senders + /// (including the original) need to be dropped in order for + /// [`Receiver::recv`] to stop blocking. fn clone(&self) -> Sender { let packet = match *unsafe { self.inner() } { Flavor::Oneshot(ref p) => { @@ -1063,9 +1100,10 @@ impl Receiver { /// corresponding channel has hung up. /// /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this - /// receiver will wake up and return that message. + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`] + /// (or [`SyncSender`]), this receiver will wake up and return that + /// message. /// /// If the corresponding [`Sender`] has disconnected, or it disconnects while /// this call is blocking, this call will wake up and return [`Err`] to @@ -1145,9 +1183,10 @@ impl Receiver { /// corresponding channel has hung up, or if it waits more than `timeout`. /// /// This function will always block the current thread if there is no data - /// available and it's possible for more data to be sent. Once a message is - /// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this - /// receiver will wake up and return that message. + /// available and it's possible for more data to be sent (at least one sender + /// still exists). Once a message is sent to the corresponding [`Sender`] + /// (or [`SyncSender`]), this receiver will wake up and return that + /// message. /// /// If the corresponding [`Sender`] has disconnected, or it disconnects while /// this call is blocking, this call will wake up and return [`Err`] to