Skip to content

Commit 3a75e80

Browse files
committedDec 10, 2018
Auto merge of #56157 - RalfJung:park, r=nagisa
expand thread::park explanation Cc @carllerche @parched @stjepang
2 parents 9567a1c + 76cd8f0 commit 3a75e80

File tree

1 file changed

+22
-5
lines changed

1 file changed

+22
-5
lines changed
 

‎src/libstd/thread/mod.rs

+22-5
Original file line numberDiff line numberDiff line change
@@ -822,9 +822,14 @@ const NOTIFIED: usize = 2;
822822
/// In other words, each [`Thread`] acts a bit like a spinlock that can be
823823
/// locked and unlocked using `park` and `unpark`.
824824
///
825+
/// Notice that being unblocked does not imply any synchronization with someone
826+
/// that unparked this thread, it could also be spurious.
827+
/// For example, it would be a valid, but inefficient, implementation to make both [`park`] and
828+
/// [`unpark`] return immediately without doing anything.
829+
///
825830
/// The API is typically used by acquiring a handle to the current thread,
826831
/// placing that handle in a shared data structure so that other threads can
827-
/// find it, and then `park`ing. When some desired condition is met, another
832+
/// find it, and then `park`ing in a loop. When some desired condition is met, another
828833
/// thread calls [`unpark`] on the handle.
829834
///
830835
/// The motivation for this design is twofold:
@@ -839,21 +844,33 @@ const NOTIFIED: usize = 2;
839844
///
840845
/// ```
841846
/// use std::thread;
847+
/// use std::sync::{Arc, atomic::{Ordering, AtomicBool}};
842848
/// use std::time::Duration;
843849
///
844-
/// let parked_thread = thread::Builder::new()
845-
/// .spawn(|| {
850+
/// let flag = Arc::new(AtomicBool::new(false));
851+
/// let flag2 = Arc::clone(&flag);
852+
///
853+
/// let parked_thread = thread::spawn(move || {
854+
/// // We want to wait until the flag is set. We *could* just spin, but using
855+
/// // park/unpark is more efficient.
856+
/// while !flag2.load(Ordering::Acquire) {
846857
/// println!("Parking thread");
847858
/// thread::park();
859+
/// // We *could* get here spuriously, i.e., way before the 10ms below are over!
860+
/// // But that is no problem, we are in a loop until the flag is set anyway.
848861
/// println!("Thread unparked");
849-
/// })
850-
/// .unwrap();
862+
/// }
863+
/// println!("Flag received");
864+
/// });
851865
///
852866
/// // Let some time pass for the thread to be spawned.
853867
/// thread::sleep(Duration::from_millis(10));
854868
///
869+
/// // Set the flag, and let the thread wake up.
855870
/// // There is no race condition here, if `unpark`
856871
/// // happens first, `park` will return immediately.
872+
/// // Hence there is no risk of a deadlock.
873+
/// flag.store(true, Ordering::Release);
857874
/// println!("Unpark the thread");
858875
/// parked_thread.thread().unpark();
859876
///

0 commit comments

Comments
 (0)
Please sign in to comment.