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