Skip to content

Commit 2d2f1a5

Browse files
authoredJun 15, 2021
Rollup merge of #80269 - pickfire:patch-4, r=joshtriplett
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.
2 parents 9089771 + 0f3c7d1 commit 2d2f1a5

File tree

1 file changed

+46
-7
lines changed
  • library/std/src/sync/mpsc

1 file changed

+46
-7
lines changed
 

‎library/std/src/sync/mpsc/mod.rs

+46-7
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,35 @@
105105
//! });
106106
//! rx.recv().unwrap();
107107
//! ```
108+
//!
109+
//! Unbounded receive loop:
110+
//!
111+
//! ```
112+
//! use std::sync::mpsc::sync_channel;
113+
//! use std::thread;
114+
//!
115+
//! let (tx, rx) = sync_channel(3);
116+
//!
117+
//! for _ in 0..3 {
118+
//! // It would be the same without thread and clone here
119+
//! // since there will still be one `tx` left.
120+
//! let tx = tx.clone();
121+
//! // cloned tx dropped within thread
122+
//! thread::spawn(move || tx.send("ok").unwrap());
123+
//! }
124+
//!
125+
//! // Drop the last sender to stop `rx` waiting for message.
126+
//! // The program will not complete if we comment this out.
127+
//! // **All** `tx` needs to be dropped for `rx` to have `Err`.
128+
//! drop(tx);
129+
//!
130+
//! // Unbounded receiver waiting for all senders to complete.
131+
//! while let Ok(msg) = rx.recv() {
132+
//! println!("{}", msg);
133+
//! }
134+
//!
135+
//! println!("completed");
136+
//! ```
108137
109138
#![stable(feature = "rust1", since = "1.0.0")]
110139

@@ -437,6 +466,9 @@ pub struct IntoIter<T> {
437466
///
438467
/// Messages can be sent through this channel with [`send`].
439468
///
469+
/// Note: all senders (the original and the clones) need to be dropped for the receiver
470+
/// to stop blocking to receive messages with [`Receiver::recv`].
471+
///
440472
/// [`send`]: Sender::send
441473
///
442474
/// # Examples
@@ -643,7 +675,7 @@ impl<T> UnsafeFlavor<T> for Receiver<T> {
643675
/// the same order as it was sent, and no [`send`] will block the calling thread
644676
/// (this channel has an "infinite buffer", unlike [`sync_channel`], which will
645677
/// block after its buffer limit is reached). [`recv`] will block until a message
646-
/// is available.
678+
/// is available while there is at least one [`Sender`] alive (including clones).
647679
///
648680
/// The [`Sender`] can be cloned to [`send`] to the same channel multiple times, but
649681
/// only one [`Receiver`] is supported.
@@ -806,6 +838,11 @@ impl<T> Sender<T> {
806838

807839
#[stable(feature = "rust1", since = "1.0.0")]
808840
impl<T> Clone for Sender<T> {
841+
/// Clone a sender to send to other threads.
842+
///
843+
/// Note, be aware of the lifetime of the sender because all senders
844+
/// (including the original) need to be dropped in order for
845+
/// [`Receiver::recv`] to stop blocking.
809846
fn clone(&self) -> Sender<T> {
810847
let packet = match *unsafe { self.inner() } {
811848
Flavor::Oneshot(ref p) => {
@@ -1064,9 +1101,10 @@ impl<T> Receiver<T> {
10641101
/// corresponding channel has hung up.
10651102
///
10661103
/// This function will always block the current thread if there is no data
1067-
/// available and it's possible for more data to be sent. Once a message is
1068-
/// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
1069-
/// receiver will wake up and return that message.
1104+
/// available and it's possible for more data to be sent (at least one sender
1105+
/// still exists). Once a message is sent to the corresponding [`Sender`]
1106+
/// (or [`SyncSender`]), this receiver will wake up and return that
1107+
/// message.
10701108
///
10711109
/// If the corresponding [`Sender`] has disconnected, or it disconnects while
10721110
/// this call is blocking, this call will wake up and return [`Err`] to
@@ -1146,9 +1184,10 @@ impl<T> Receiver<T> {
11461184
/// corresponding channel has hung up, or if it waits more than `timeout`.
11471185
///
11481186
/// This function will always block the current thread if there is no data
1149-
/// available and it's possible for more data to be sent. Once a message is
1150-
/// sent to the corresponding [`Sender`] (or [`SyncSender`]), then this
1151-
/// receiver will wake up and return that message.
1187+
/// available and it's possible for more data to be sent (at least one sender
1188+
/// still exists). Once a message is sent to the corresponding [`Sender`]
1189+
/// (or [`SyncSender`]), this receiver will wake up and return that
1190+
/// message.
11521191
///
11531192
/// If the corresponding [`Sender`] has disconnected, or it disconnects while
11541193
/// this call is blocking, this call will wake up and return [`Err`] to

0 commit comments

Comments
 (0)