Skip to content

Commit

Permalink
Rollup merge of #80269 - pickfire:patch-4, r=joshtriplett
Browse files Browse the repository at this point in the history
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.

Maybe it would be better to show an example of the pattern where `drop(tx)` is used when it is being cloned multiple times? Although I have seen it in quite a few articles but I am surprised that this part is not very clear with the current words without careful reading.

> If the corresponding Sender has disconnected, or it disconnects while this call is blocking, this call will wake up and return Err to indicate that no more messages can ever be received on this channel. However, since channels are buffered, messages sent before the disconnect will still be properly received.

Some words there may seemed similar if I carefully read and relate it but if I am new, I probably does not know "drop" makes it "disconnected". So I mention the words "drop" and "alive" to make it more relatable to lifetime.
  • Loading branch information
JohnTitor committed Jun 15, 2021
2 parents 9089771 + 0f3c7d1 commit 2d2f1a5
Showing 1 changed file with 46 additions and 7 deletions.
53 changes: 46 additions & 7 deletions library/std/src/sync/mpsc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]

Expand Down Expand Up @@ -437,6 +466,9 @@ pub struct IntoIter<T> {
///
/// 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
Expand Down Expand Up @@ -643,7 +675,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
/// 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.
Expand Down Expand Up @@ -806,6 +838,11 @@ impl<T> Sender<T> {

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> Clone for Sender<T> {
/// 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<T> {
let packet = match *unsafe { self.inner() } {
Flavor::Oneshot(ref p) => {
Expand Down Expand Up @@ -1064,9 +1101,10 @@ impl<T> Receiver<T> {
/// 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
Expand Down Expand Up @@ -1146,9 +1184,10 @@ impl<T> Receiver<T> {
/// 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
Expand Down

0 comments on commit 2d2f1a5

Please sign in to comment.