Auto merge of #56157 - RalfJung:park, r=nagisa

expand thread::park explanation

Cc @carllerche @parched @stjepang
This commit is contained in:
bors 2018-12-10 12:19:47 +00:00
commit 3a75e80557

View File

@ -822,9 +822,14 @@ const NOTIFIED: usize = 2;
/// In other words, each [`Thread`] acts a bit like a spinlock that can be /// In other words, each [`Thread`] acts a bit like a spinlock that can be
/// locked and unlocked using `park` and `unpark`. /// 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, /// 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 /// 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. /// thread calls [`unpark`] on the handle.
/// ///
/// The motivation for this design is twofold: /// The motivation for this design is twofold:
@ -839,21 +844,33 @@ const NOTIFIED: usize = 2;
/// ///
/// ``` /// ```
/// use std::thread; /// use std::thread;
/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
/// use std::time::Duration; /// use std::time::Duration;
/// ///
/// let parked_thread = thread::Builder::new() /// let flag = Arc::new(AtomicBool::new(false));
/// .spawn(|| { /// 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"); /// println!("Parking thread");
/// thread::park(); /// 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"); /// println!("Thread unparked");
/// }) /// }
/// .unwrap(); /// println!("Flag received");
/// });
/// ///
/// // Let some time pass for the thread to be spawned. /// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10)); /// thread::sleep(Duration::from_millis(10));
/// ///
/// // Set the flag, and let the thread wake up.
/// // There is no race condition here, if `unpark` /// // There is no race condition here, if `unpark`
/// // happens first, `park` will return immediately. /// // happens first, `park` will return immediately.
/// // Hence there is no risk of a deadlock.
/// flag.store(true, Ordering::Release);
/// println!("Unpark the thread"); /// println!("Unpark the thread");
/// parked_thread.thread().unpark(); /// parked_thread.thread().unpark();
/// ///