Skip to content

Commit

Permalink
Rollup merge of rust-lang#41809 - gamazeps:thread-docs, r=steveklabnik
Browse files Browse the repository at this point in the history
[DOC] Improve the thread::park and thread::unpark documentation

Part of rust-lang#29378 .

Takes care of the documentation for `park`, `park_duration` and also improves the `unpark` example.

- `park should` have its module documentation inlined here, and cleaned up.
- `park_timeout` could use links to `park`.
  • Loading branch information
frewsxcv committed May 10, 2017
2 parents 126feca + afe74c3 commit 2806ba0
Showing 1 changed file with 91 additions and 61 deletions.
152 changes: 91 additions & 61 deletions src/libstd/thread/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,41 +96,6 @@
//! The [`thread::current`] function is available even for threads not spawned
//! by the APIs of this module.
//!
//! ## Blocking support: park and unpark
//!
//! Every thread is equipped with some basic low-level blocking support, via the
//! [`thread::park`][`park`] function and [`thread::Thread::unpark()`][`unpark`]
//! method. [`park`] blocks the current thread, which can then be resumed from
//! another thread by calling the [`unpark`] method on the blocked thread's handle.
//!
//! Conceptually, each [`Thread`] handle has an associated token, which is
//! initially not present:
//!
//! * The [`thread::park`][`park`] function blocks the current thread unless or until
//! the token is available for its thread handle, at which point it atomically
//! consumes the token. It may also return *spuriously*, without consuming the
//! token. [`thread::park_timeout`] does the same, but allows specifying a
//! maximum time to block the thread for.
//!
//! * The [`unpark`] method on a [`Thread`] atomically makes the token available
//! if it wasn't already.
//!
//! In other words, each [`Thread`] acts a bit like a semaphore with initial count
//! 0, except that the semaphore is *saturating* (the count cannot go above 1),
//! and can return spuriously.
//!
//! 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
//! thread calls [`unpark`] on the handle.
//!
//! The motivation for this design is twofold:
//!
//! * It avoids the need to allocate mutexes and condvars when building new
//! synchronization primitives; the threads already provide basic blocking/signaling.
//!
//! * It can be implemented very efficiently on many platforms.
//!
//! ## Thread-local storage
//!
//! This module also provides an implementation of thread-local storage for Rust
Expand Down Expand Up @@ -566,23 +531,72 @@ pub fn sleep(dur: Duration) {

/// Blocks unless or until the current thread's token is made available.
///
/// Every thread is equipped with some basic low-level blocking support, via
/// the `park()` function and the [`unpark`][unpark] method. These can be
/// used as a more CPU-efficient implementation of a spinlock.
/// A call to `park` does not guarantee that the thread will remain parked
/// forever, and callers should be prepared for this possibility.
///
/// # park and unpark
///
/// Every thread is equipped with some basic low-level blocking support, via the
/// [`thread::park`][`park`] function and [`thread::Thread::unpark`][`unpark`]
/// method. [`park`] blocks the current thread, which can then be resumed from
/// another thread by calling the [`unpark`] method on the blocked thread's
/// handle.
///
/// Conceptually, each [`Thread`] handle has an associated token, which is
/// initially not present:
///
/// [unpark]: struct.Thread.html#method.unpark
/// * The [`thread::park`][`park`] function blocks the current thread unless or
/// until the token is available for its thread handle, at which point it
/// atomically consumes the token. It may also return *spuriously*, without
/// consuming the token. [`thread::park_timeout`] does the same, but allows
/// specifying a maximum time to block the thread for.
///
/// * The [`unpark`] method on a [`Thread`] atomically makes the token available
/// if it wasn't already.
///
/// In other words, each [`Thread`] acts a bit like a spinlock that can be
/// locked and unlocked using `park` and `unpark`.
///
/// 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 parking (in a loop with a check for the token actually
/// being acquired).
/// find it, and then `park`ing. When some desired condition is met, another
/// thread calls [`unpark`] on the handle.
///
/// A call to `park` does not guarantee that the thread will remain parked
/// forever, and callers should be prepared for this possibility.
/// The motivation for this design is twofold:
///
/// * It avoids the need to allocate mutexes and condvars when building new
/// synchronization primitives; the threads already provide basic
/// blocking/signaling.
///
/// See the [module documentation][thread] for more detail.
/// * It can be implemented very efficiently on many platforms.
///
/// [thread]: index.html
/// # Examples
///
/// ```
/// use std::thread;
/// use std::time::Duration;
///
/// let parked_thread = thread::Builder::new()
/// .spawn(|| {
/// println!("Parking thread");
/// thread::park();
/// println!("Thread unparked");
/// })
/// .unwrap();
///
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
/// parked_thread.join().unwrap();
/// ```
///
/// [`Thread`]: ../../std/thread/struct.Thread.html
/// [`park`]: ../../std/thread/fn.park.html
/// [`unpark`]: ../../std/thread/struct.Thread.html#method.unpark
/// [`thread::park_timeout`]: ../../std/thread/fn.park_timeout.html
//
// The implementation currently uses the trivial strategy of a Mutex+Condvar
// with wakeup flag, which does not actually allow spurious wakeups. In the
Expand All @@ -599,21 +613,21 @@ pub fn park() {
*guard = false;
}

/// Use [park_timeout].
/// Use [`park_timeout`].
///
/// Blocks unless or until the current thread's token is made available or
/// the specified duration has been reached (may wake spuriously).
///
/// The semantics of this function are equivalent to `park()` except that the
/// thread will be blocked for roughly no longer than `ms`. This method
/// should not be used for precise timing due to anomalies such as
/// The semantics of this function are equivalent to [`park`] except
/// that the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum
/// amount of time waited to be precisely `ms` long.
///
/// See the [module documentation][thread] for more detail.
/// See the [park documentation][`park`] for more detail.
///
/// [thread]: index.html
/// [park_timeout]: fn.park_timeout.html
/// [`park_timeout`]: fn.park_timeout.html
/// [`park`]: ../../std/thread/fn.park.html
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::park_timeout`")]
pub fn park_timeout_ms(ms: u32) {
Expand All @@ -623,13 +637,13 @@ pub fn park_timeout_ms(ms: u32) {
/// Blocks unless or until the current thread's token is made available or
/// the specified duration has been reached (may wake spuriously).
///
/// The semantics of this function are equivalent to `park()` except that the
/// thread will be blocked for roughly no longer than `dur`. This method
/// should not be used for precise timing due to anomalies such as
/// The semantics of this function are equivalent to [`park`][park] except
/// that the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum
/// amount of time waited to be precisely `dur` long.
///
/// See the module doc for more detail.
/// See the [park dococumentation][park] for more details.
///
/// # Platform behavior
///
Expand All @@ -654,6 +668,8 @@ pub fn park_timeout_ms(ms: u32) {
/// park_timeout(timeout);
/// }
/// ```
///
/// [park]: fn.park.html
#[stable(feature = "park_timeout", since = "1.4.0")]
pub fn park_timeout(dur: Duration) {
let thread = current();
Expand Down Expand Up @@ -775,22 +791,36 @@ impl Thread {

/// Atomically makes the handle's token available if it is not already.
///
/// See the module doc for more detail.
/// Every thread is equipped with some basic low-level blocking support, via
/// the [`park`][park] function and the `unpark()` method. These can be
/// used as a more CPU-efficient implementation of a spinlock.
///
/// See the [park documentation][park] for more details.
///
/// # Examples
///
/// ```
/// use std::thread;
/// use std::time::Duration;
///
/// let handler = thread::Builder::new()
/// let parked_thread = thread::Builder::new()
/// .spawn(|| {
/// let thread = thread::current();
/// thread.unpark();
/// println!("Parking thread");
/// thread::park();
/// println!("Thread unparked");
/// })
/// .unwrap();
///
/// handler.join().unwrap();
/// // Let some time pass for the thread to be spawned.
/// thread::sleep(Duration::from_millis(10));
///
/// println!("Unpark the thread");
/// parked_thread.thread().unpark();
///
/// parked_thread.join().unwrap();
/// ```
///
/// [park]: fn.park.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn unpark(&self) {
let mut guard = self.inner.lock.lock().unwrap();
Expand Down

0 comments on commit 2806ba0

Please sign in to comment.