diff options
| author | bors <bors@rust-lang.org> | 2018-12-10 12:19:47 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-12-10 12:19:47 +0000 |
| commit | 3a75e80557a103497cffbcab395a2f37061a77ea (patch) | |
| tree | 177dcf312c7fb1ff47b4561f0616cf321385e9d3 /src/libstd/thread/mod.rs | |
| parent | 9567a1cf5993d46c00ee2f2b363f3eabe90b2a0e (diff) | |
| parent | 76cd8f05945e5edd8272e2e8c8f41ffd0182f403 (diff) | |
| download | rust-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/thread/mod.rs')
| -rw-r--r-- | src/libstd/thread/mod.rs | 27 |
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(); /// |
