about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-12-10 12:19:47 +0000
committerbors <bors@rust-lang.org>2018-12-10 12:19:47 +0000
commit3a75e80557a103497cffbcab395a2f37061a77ea (patch)
tree177dcf312c7fb1ff47b4561f0616cf321385e9d3 /src/libstd
parent9567a1cf5993d46c00ee2f2b363f3eabe90b2a0e (diff)
parent76cd8f05945e5edd8272e2e8c8f41ffd0182f403 (diff)
downloadrust-3a75e80557a103497cffbcab395a2f37061a77ea.tar.gz
rust-3a75e80557a103497cffbcab395a2f37061a77ea.zip
Auto merge of #56157 - RalfJung:park, r=nagisa
expand thread::park explanation

Cc @carllerche @parched @stjepang
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/thread/mod.rs27
1 files changed, 22 insertions, 5 deletions
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 194e2881df3..b70dfc46af5 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -822,9 +822,14 @@ const NOTIFIED: usize = 2;
 /// In other words, each [`Thread`] acts a bit like a spinlock that can be
 /// locked and unlocked using `park` and `unpark`.
 ///
+/// Notice that being unblocked does not imply any synchronization with someone
+/// that unparked this thread, it could also be spurious.
+/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and
+/// [`unpark`] return immediately without doing anything.
+///
 /// The API is typically used by acquiring a handle to the current thread,
 /// placing that handle in a shared data structure so that other threads can
-/// find it, and then `park`ing. When some desired condition is met, another
+/// find it, and then `park`ing in a loop. When some desired condition is met, another
 /// thread calls [`unpark`] on the handle.
 ///
 /// The motivation for this design is twofold:
@@ -839,21 +844,33 @@ const NOTIFIED: usize = 2;
 ///
 /// ```
 /// use std::thread;
+/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
 /// use std::time::Duration;
 ///
-/// let parked_thread = thread::Builder::new()
-///     .spawn(|| {
+/// let flag = Arc::new(AtomicBool::new(false));
+/// let flag2 = Arc::clone(&flag);
+///
+/// let parked_thread = thread::spawn(move || {
+///     // We want to wait until the flag is set.  We *could* just spin, but using
+///     // park/unpark is more efficient.
+///     while !flag2.load(Ordering::Acquire) {
 ///         println!("Parking thread");
 ///         thread::park();
+///         // We *could* get here spuriously, i.e., way before the 10ms below are over!
+///         // But that is no problem, we are in a loop until the flag is set anyway.
 ///         println!("Thread unparked");
-///     })
-///     .unwrap();
+///     }
+///     println!("Flag received");
+/// });
 ///
 /// // Let some time pass for the thread to be spawned.
 /// thread::sleep(Duration::from_millis(10));
 ///
+/// // Set the flag, and let the thread wake up.
 /// // There is no race condition here, if `unpark`
 /// // happens first, `park` will return immediately.
+/// // Hence there is no risk of a deadlock.
+/// flag.store(true, Ordering::Release);
 /// println!("Unpark the thread");
 /// parked_thread.thread().unpark();
 ///