Skip to main content

std/thread/
join_handle.rs

1use super::Result;
2use super::lifecycle::JoinInner;
3use super::thread::Thread;
4use crate::fmt;
5use crate::sys::{AsInner, IntoInner, thread as imp};
6
7/// An owned permission to join on a thread (block on its termination).
8///
9/// A `JoinHandle` *detaches* the associated thread when it is dropped, which
10/// means that there is no longer any handle to the thread and no way to `join`
11/// on it.
12///
13/// Due to platform restrictions, it is not possible to [`Clone`] this
14/// handle: the ability to join a thread is a uniquely-owned permission.
15///
16/// This `struct` is created by the [`thread::spawn`] function and the
17/// [`thread::Builder::spawn`] method.
18///
19/// # Examples
20///
21/// Creation from [`thread::spawn`]:
22///
23/// ```
24/// use std::thread;
25///
26/// let join_handle: thread::JoinHandle<_> = thread::spawn(|| {
27///     // some work here
28/// });
29/// ```
30///
31/// Creation from [`thread::Builder::spawn`]:
32///
33/// ```
34/// use std::thread;
35///
36/// let builder = thread::Builder::new();
37///
38/// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
39///     // some work here
40/// }).unwrap();
41/// ```
42///
43/// A thread being detached and outliving the thread that spawned it:
44///
45/// ```no_run
46/// use std::thread;
47/// use std::time::Duration;
48///
49/// let original_thread = thread::spawn(|| {
50///     let _detached_thread = thread::spawn(|| {
51///         // Here we sleep to make sure that the first thread returns before.
52///         thread::sleep(Duration::from_millis(10));
53///         // This will be called, even though the JoinHandle is dropped.
54///         println!("♫ Still alive ♫");
55///     });
56/// });
57///
58/// original_thread.join().expect("The thread being joined has panicked");
59/// println!("Original thread is joined.");
60///
61/// // We make sure that the new thread has time to run, before the main
62/// // thread returns.
63///
64/// thread::sleep(Duration::from_millis(1000));
65/// ```
66///
67/// [`thread::Builder::spawn`]: super::Builder::spawn
68/// [`thread::spawn`]: super::spawn
69#[stable(feature = "rust1", since = "1.0.0")]
70#[cfg_attr(target_os = "teeos", must_use)]
71pub struct JoinHandle<T>(pub(super) JoinInner<'static, T>);
72
73#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
74unsafe impl<T> Send for JoinHandle<T> {}
75#[stable(feature = "joinhandle_impl_send_sync", since = "1.29.0")]
76unsafe impl<T> Sync for JoinHandle<T> {}
77
78impl<T> JoinHandle<T> {
79    /// Extracts a handle to the underlying thread.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use std::thread;
85    ///
86    /// let builder = thread::Builder::new();
87    ///
88    /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
89    ///     // some work here
90    /// }).unwrap();
91    ///
92    /// let thread = join_handle.thread();
93    /// println!("thread id: {:?}", thread.id());
94    /// ```
95    #[stable(feature = "rust1", since = "1.0.0")]
96    #[must_use]
97    pub fn thread(&self) -> &Thread {
98        self.0.thread()
99    }
100
101    /// Waits for the associated thread to finish.
102    ///
103    /// This function will return immediately if the associated thread has already finished.
104    /// Otherwise, it fully waits for the thread to finish, including all destructors
105    /// for thread-local variables that might be running after the main function of the thread.
106    ///
107    /// In terms of [atomic memory orderings],  the completion of the associated
108    /// thread synchronizes with this function returning. In other words, all
109    /// operations performed by that thread [happen
110    /// before](https://doc.rust-lang.org/nomicon/atomics.html#data-accesses) all
111    /// operations that happen after `join` returns.
112    ///
113    /// If the associated thread panics, [`Err`] is returned with the parameter given
114    /// to [`panic!`] (though see the Notes below).
115    ///
116    /// [`Err`]: crate::result::Result::Err
117    /// [atomic memory orderings]: crate::sync::atomic
118    ///
119    /// # Panics
120    ///
121    /// This function may panic on some platforms if a thread attempts to join
122    /// itself or otherwise may create a deadlock with joining threads.
123    ///
124    /// # Examples
125    ///
126    /// ```
127    /// use std::thread;
128    ///
129    /// let builder = thread::Builder::new();
130    ///
131    /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
132    ///     // some work here
133    /// }).unwrap();
134    /// join_handle.join().expect("Couldn't join on the associated thread");
135    /// ```
136    ///
137    /// # Notes
138    ///
139    /// If a "foreign" unwinding operation (e.g. an exception thrown from C++
140    /// code, or a `panic!` in Rust code compiled or linked with a different
141    /// runtime) unwinds all the way to the thread root, the process may be
142    /// aborted; see the Notes on [`thread::spawn`]. If the process is not
143    /// aborted, this function will return a `Result::Err` containing an opaque
144    /// type.
145    ///
146    /// [`catch_unwind`]: ../../std/panic/fn.catch_unwind.html
147    /// [`thread::spawn`]: super::spawn
148    #[stable(feature = "rust1", since = "1.0.0")]
149    pub fn join(self) -> Result<T> {
150        self.0.join()
151    }
152
153    /// Checks if the associated thread has finished running its main function.
154    ///
155    /// `is_finished` supports implementing a non-blocking join operation, by checking
156    /// `is_finished`, and calling `join` if it returns `true`. This function does not block. To
157    /// block while waiting on the thread to finish, use [`join`][Self::join].
158    ///
159    /// This might return `true` for a brief moment after the thread's main
160    /// function has returned, but before the thread itself has stopped running.
161    /// However, once this returns `true`, [`join`][Self::join] can be expected
162    /// to return quickly, without blocking for any significant amount of time.
163    #[stable(feature = "thread_is_running", since = "1.61.0")]
164    pub fn is_finished(&self) -> bool {
165        self.0.is_finished()
166    }
167}
168
169impl<T> AsInner<imp::Thread> for JoinHandle<T> {
170    fn as_inner(&self) -> &imp::Thread {
171        self.0.as_inner()
172    }
173}
174
175impl<T> IntoInner<imp::Thread> for JoinHandle<T> {
176    fn into_inner(self) -> imp::Thread {
177        self.0.into_inner()
178    }
179}
180
181#[stable(feature = "std_debug", since = "1.16.0")]
182impl<T> fmt::Debug for JoinHandle<T> {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        f.debug_struct("JoinHandle").finish_non_exhaustive()
185    }
186}