Rollup merge of #87848 - godmar:@godmar/thread-join-documentation-fix, r=joshtriplett
removed references to parent/child from std::thread documentation - also clarifies how thread.join and detaching of threads works - the previous prose implied that there is a relationship between a spawning thread and the thread being spawned, and that "child" threads couldn't outlive their "parents" unless detached, which is incorrect.
This commit is contained in:
commit
6412bf98ea
1 changed files with 40 additions and 31 deletions
|
@ -28,7 +28,7 @@
|
||||||
//! When the main thread of a Rust program terminates, the entire program shuts
|
//! When the main thread of a Rust program terminates, the entire program shuts
|
||||||
//! down, even if other threads are still running. However, this module provides
|
//! down, even if other threads are still running. However, this module provides
|
||||||
//! convenient facilities for automatically waiting for the termination of a
|
//! convenient facilities for automatically waiting for the termination of a
|
||||||
//! child thread (i.e., join).
|
//! thread (i.e., join).
|
||||||
//!
|
//!
|
||||||
//! ## Spawning a thread
|
//! ## Spawning a thread
|
||||||
//!
|
//!
|
||||||
|
@ -42,38 +42,43 @@
|
||||||
//! });
|
//! });
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! In this example, the spawned thread is "detached" from the current
|
//! In this example, the spawned thread is "detached," which means that there is
|
||||||
//! thread. This means that it can outlive its parent (the thread that spawned
|
//! no way for the program to learn when the spawned thread completes or otherwise
|
||||||
//! it), unless this parent is the main thread.
|
//! terminates.
|
||||||
//!
|
//!
|
||||||
//! The parent thread can also wait on the completion of the child
|
//! To learn when a thread completes, it is necessary to capture the [`JoinHandle`]
|
||||||
//! thread; a call to [`spawn`] produces a [`JoinHandle`], which provides
|
//! object that is returned by the call to [`spawn`], which provides
|
||||||
//! a `join` method for waiting:
|
//! a `join` method that allows the caller to wait for the completion of the
|
||||||
|
//! spawned thread:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! use std::thread;
|
//! use std::thread;
|
||||||
//!
|
//!
|
||||||
//! let child = thread::spawn(move || {
|
//! let thread_join_handle = thread::spawn(move || {
|
||||||
//! // some work here
|
//! // some work here
|
||||||
//! });
|
//! });
|
||||||
//! // some work here
|
//! // some work here
|
||||||
//! let res = child.join();
|
//! let res = thread_join_handle.join();
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final
|
//! The [`join`] method returns a [`thread::Result`] containing [`Ok`] of the final
|
||||||
//! value produced by the child thread, or [`Err`] of the value given to
|
//! value produced by the spawned thread, or [`Err`] of the value given to
|
||||||
//! a call to [`panic!`] if the child panicked.
|
//! a call to [`panic!`] if the thread panicked.
|
||||||
|
//!
|
||||||
|
//! Note that there is no parent/child relationship between a thread that spawns a
|
||||||
|
//! new thread and the thread being spawned. In particular, the spawned thread may or
|
||||||
|
//! may not outlive the spawning thread, unless the spawning thread is the main thread.
|
||||||
//!
|
//!
|
||||||
//! ## Configuring threads
|
//! ## Configuring threads
|
||||||
//!
|
//!
|
||||||
//! A new thread can be configured before it is spawned via the [`Builder`] type,
|
//! A new thread can be configured before it is spawned via the [`Builder`] type,
|
||||||
//! which currently allows you to set the name and stack size for the child thread:
|
//! which currently allows you to set the name and stack size for the thread:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```rust
|
||||||
//! # #![allow(unused_must_use)]
|
//! # #![allow(unused_must_use)]
|
||||||
//! use std::thread;
|
//! use std::thread;
|
||||||
//!
|
//!
|
||||||
//! thread::Builder::new().name("child1".to_string()).spawn(move || {
|
//! thread::Builder::new().name("thread1".to_string()).spawn(move || {
|
||||||
//! println!("Hello, world!");
|
//! println!("Hello, world!");
|
||||||
//! });
|
//! });
|
||||||
//! ```
|
//! ```
|
||||||
|
@ -344,7 +349,7 @@ impl Builder {
|
||||||
/// The spawned thread may outlive the caller (unless the caller thread
|
/// The spawned thread may outlive the caller (unless the caller thread
|
||||||
/// is the main thread; the whole process is terminated when the main
|
/// is the main thread; the whole process is terminated when the main
|
||||||
/// thread finishes). The join handle can be used to block on
|
/// thread finishes). The join handle can be used to block on
|
||||||
/// termination of the child thread, including recovering its panics.
|
/// termination of the spawned thread, including recovering its panics.
|
||||||
///
|
///
|
||||||
/// For a more complete documentation see [`thread::spawn`][`spawn`].
|
/// For a more complete documentation see [`thread::spawn`][`spawn`].
|
||||||
///
|
///
|
||||||
|
@ -389,7 +394,7 @@ impl Builder {
|
||||||
/// The spawned thread may outlive the caller (unless the caller thread
|
/// The spawned thread may outlive the caller (unless the caller thread
|
||||||
/// is the main thread; the whole process is terminated when the main
|
/// is the main thread; the whole process is terminated when the main
|
||||||
/// thread finishes). The join handle can be used to block on
|
/// thread finishes). The join handle can be used to block on
|
||||||
/// termination of the child thread, including recovering its panics.
|
/// termination of the spawned thread, including recovering its panics.
|
||||||
///
|
///
|
||||||
/// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`],
|
/// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`],
|
||||||
/// except for the relaxed lifetime bounds, which render it unsafe.
|
/// except for the relaxed lifetime bounds, which render it unsafe.
|
||||||
|
@ -516,15 +521,16 @@ impl Builder {
|
||||||
|
|
||||||
/// Spawns a new thread, returning a [`JoinHandle`] for it.
|
/// Spawns a new thread, returning a [`JoinHandle`] for it.
|
||||||
///
|
///
|
||||||
/// The join handle will implicitly *detach* the child thread upon being
|
/// The join handle provides a [`join`] method that can be used to join the spawned
|
||||||
/// dropped. In this case, the child thread may outlive the parent (unless
|
/// thread. If the spawned thread panics, [`join`] will return an [`Err`] containing
|
||||||
/// the parent thread is the main thread; the whole process is terminated when
|
/// the argument given to [`panic!`].
|
||||||
/// the main thread finishes). Additionally, the join handle provides a [`join`]
|
|
||||||
/// method that can be used to join the child thread. If the child thread
|
|
||||||
/// panics, [`join`] will return an [`Err`] containing the argument given to
|
|
||||||
/// [`panic!`].
|
|
||||||
///
|
///
|
||||||
/// This will create a thread using default parameters of [`Builder`], if you
|
/// If the join handle is dropped, the spawned thread will implicitly be *detached*.
|
||||||
|
/// In this case, the spawned thread may no longer be joined.
|
||||||
|
/// (It is the responsibility of the program to either eventually join threads it
|
||||||
|
/// creates or detach them; otherwise, a resource leak will result.)
|
||||||
|
///
|
||||||
|
/// This call will create a thread using default parameters of [`Builder`], if you
|
||||||
/// want to specify the stack size or the name of the thread, use this API
|
/// want to specify the stack size or the name of the thread, use this API
|
||||||
/// instead.
|
/// instead.
|
||||||
///
|
///
|
||||||
|
@ -533,8 +539,8 @@ impl Builder {
|
||||||
///
|
///
|
||||||
/// - The `'static` constraint means that the closure and its return value
|
/// - The `'static` constraint means that the closure and its return value
|
||||||
/// must have a lifetime of the whole program execution. The reason for this
|
/// must have a lifetime of the whole program execution. The reason for this
|
||||||
/// is that threads can `detach` and outlive the lifetime they have been
|
/// is that threads can outlive the lifetime they have been created in.
|
||||||
/// created in.
|
///
|
||||||
/// Indeed if the thread, and by extension its return value, can outlive their
|
/// Indeed if the thread, and by extension its return value, can outlive their
|
||||||
/// caller, we need to make sure that they will be valid afterwards, and since
|
/// caller, we need to make sure that they will be valid afterwards, and since
|
||||||
/// we *can't* know when it will return we need to have them valid as long as
|
/// we *can't* know when it will return we need to have them valid as long as
|
||||||
|
@ -1236,10 +1242,10 @@ impl fmt::Debug for Thread {
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
|
pub type Result<T> = crate::result::Result<T, Box<dyn Any + Send + 'static>>;
|
||||||
|
|
||||||
// This packet is used to communicate the return value between the child thread
|
// This packet is used to communicate the return value between the spawned thread
|
||||||
// and the parent thread. Memory is shared through the `Arc` within and there's
|
// and the rest of the program. Memory is shared through the `Arc` within and there's
|
||||||
// no need for a mutex here because synchronization happens with `join()` (the
|
// no need for a mutex here because synchronization happens with `join()` (the
|
||||||
// parent thread never reads this packet until the child has exited).
|
// caller will never read this packet until the thread has exited).
|
||||||
//
|
//
|
||||||
// This packet itself is then stored into a `JoinInner` which in turns is placed
|
// This packet itself is then stored into a `JoinInner` which in turns is placed
|
||||||
// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to
|
// in `JoinHandle` and `JoinGuard`. Due to the usage of `UnsafeCell` we need to
|
||||||
|
@ -1303,7 +1309,7 @@ impl<T> JoinInner<T> {
|
||||||
/// }).unwrap();
|
/// }).unwrap();
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// Child being detached and outliving its parent:
|
/// A thread being detached and outliving the thread that spawned it:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// use std::thread;
|
/// use std::thread;
|
||||||
|
@ -1361,12 +1367,15 @@ impl<T> JoinHandle<T> {
|
||||||
|
|
||||||
/// Waits for the associated thread to finish.
|
/// Waits for the associated thread to finish.
|
||||||
///
|
///
|
||||||
|
/// This function will return immediately if the associated thread has already finished.
|
||||||
|
///
|
||||||
/// In terms of [atomic memory orderings], the completion of the associated
|
/// In terms of [atomic memory orderings], the completion of the associated
|
||||||
/// thread synchronizes with this function returning. In other words, all
|
/// thread synchronizes with this function returning. In other words, all
|
||||||
/// operations performed by that thread are ordered before all
|
/// operations performed by that thread [happen
|
||||||
|
/// before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses) all
|
||||||
/// operations that happen after `join` returns.
|
/// operations that happen after `join` returns.
|
||||||
///
|
///
|
||||||
/// If the child thread panics, [`Err`] is returned with the parameter given
|
/// If the associated thread panics, [`Err`] is returned with the parameter given
|
||||||
/// to [`panic!`].
|
/// to [`panic!`].
|
||||||
///
|
///
|
||||||
/// [`Err`]: crate::result::Result::Err
|
/// [`Err`]: crate::result::Result::Err
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue