std/thread/
builder.rs

1use super::join_handle::JoinHandle;
2use super::lifecycle::spawn_unchecked;
3use crate::io;
4
5/// Thread factory, which can be used in order to configure the properties of
6/// a new thread.
7///
8/// Methods can be chained on it in order to configure it.
9///
10/// The two configurations available are:
11///
12/// - [`name`]: specifies an [associated name for the thread][naming-threads]
13/// - [`stack_size`]: specifies the [desired stack size for the thread][stack-size]
14///
15/// The [`spawn`] method will take ownership of the builder and create an
16/// [`io::Result`] to the thread handle with the given configuration.
17///
18/// The [`thread::spawn`] free function uses a `Builder` with default
19/// configuration and [`unwrap`]s its return value.
20///
21/// You may want to use [`spawn`] instead of [`thread::spawn`], when you want
22/// to recover from a failure to launch a thread, indeed the free function will
23/// panic where the `Builder` method will return a [`io::Result`].
24///
25/// # Examples
26///
27/// ```
28/// use std::thread;
29///
30/// let builder = thread::Builder::new();
31///
32/// let handler = builder.spawn(|| {
33///     // thread code
34/// }).unwrap();
35///
36/// handler.join().unwrap();
37/// ```
38///
39/// [`stack_size`]: Builder::stack_size
40/// [`name`]: Builder::name
41/// [`spawn`]: Builder::spawn
42/// [`thread::spawn`]: super::spawn
43/// [`io::Result`]: crate::io::Result
44/// [`unwrap`]: crate::result::Result::unwrap
45/// [naming-threads]: ./index.html#naming-threads
46/// [stack-size]: ./index.html#stack-size
47#[must_use = "must eventually spawn the thread"]
48#[stable(feature = "rust1", since = "1.0.0")]
49#[derive(Debug)]
50pub struct Builder {
51    /// A name for the thread-to-be, for identification in panic messages
52    pub(super) name: Option<String>,
53    /// The size of the stack for the spawned thread in bytes
54    pub(super) stack_size: Option<usize>,
55    /// Skip running and inheriting the thread spawn hooks
56    pub(super) no_hooks: bool,
57}
58
59impl Builder {
60    /// Generates the base configuration for spawning a thread, from which
61    /// configuration methods can be chained.
62    ///
63    /// # Examples
64    ///
65    /// ```
66    /// use std::thread;
67    ///
68    /// let builder = thread::Builder::new()
69    ///                               .name("foo".into())
70    ///                               .stack_size(32 * 1024);
71    ///
72    /// let handler = builder.spawn(|| {
73    ///     // thread code
74    /// }).unwrap();
75    ///
76    /// handler.join().unwrap();
77    /// ```
78    #[stable(feature = "rust1", since = "1.0.0")]
79    pub fn new() -> Builder {
80        Builder { name: None, stack_size: None, no_hooks: false }
81    }
82
83    /// Names the thread-to-be. Currently the name is used for identification
84    /// only in panic messages.
85    ///
86    /// The name must not contain null bytes (`\0`).
87    ///
88    /// For more information about named threads, see
89    /// [this module-level documentation][naming-threads].
90    ///
91    /// # Examples
92    ///
93    /// ```
94    /// use std::thread;
95    ///
96    /// let builder = thread::Builder::new()
97    ///     .name("foo".into());
98    ///
99    /// let handler = builder.spawn(|| {
100    ///     assert_eq!(thread::current().name(), Some("foo"))
101    /// }).unwrap();
102    ///
103    /// handler.join().unwrap();
104    /// ```
105    ///
106    /// [naming-threads]: ./index.html#naming-threads
107    #[stable(feature = "rust1", since = "1.0.0")]
108    pub fn name(mut self, name: String) -> Builder {
109        self.name = Some(name);
110        self
111    }
112
113    /// Sets the size of the stack (in bytes) for the new thread.
114    ///
115    /// The actual stack size may be greater than this value if
116    /// the platform specifies a minimal stack size.
117    ///
118    /// For more information about the stack size for threads, see
119    /// [this module-level documentation][stack-size].
120    ///
121    /// # Examples
122    ///
123    /// ```
124    /// use std::thread;
125    ///
126    /// let builder = thread::Builder::new().stack_size(32 * 1024);
127    /// ```
128    ///
129    /// [stack-size]: ./index.html#stack-size
130    #[stable(feature = "rust1", since = "1.0.0")]
131    pub fn stack_size(mut self, size: usize) -> Builder {
132        self.stack_size = Some(size);
133        self
134    }
135
136    /// Disables running and inheriting [spawn hooks].
137    ///
138    /// Use this if the parent thread is in no way relevant for the child thread.
139    /// For example, when lazily spawning threads for a thread pool.
140    ///
141    /// [spawn hooks]: super::add_spawn_hook
142    #[unstable(feature = "thread_spawn_hook", issue = "132951")]
143    pub fn no_hooks(mut self) -> Builder {
144        self.no_hooks = true;
145        self
146    }
147
148    /// Spawns a new thread by taking ownership of the `Builder`, and returns an
149    /// [`io::Result`] to its [`JoinHandle`].
150    ///
151    /// The spawned thread may outlive the caller (unless the caller thread
152    /// is the main thread; the whole process is terminated when the main
153    /// thread finishes). The join handle can be used to block on
154    /// termination of the spawned thread, including recovering its panics.
155    ///
156    /// For a more complete documentation see [`thread::spawn`].
157    ///
158    /// # Errors
159    ///
160    /// Unlike the [`spawn`] free function, this method yields an
161    /// [`io::Result`] to capture any failure to create the thread at
162    /// the OS level.
163    ///
164    /// [`io::Result`]: crate::io::Result
165    ///
166    /// # Panics
167    ///
168    /// Panics if a thread name was set and it contained null bytes.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// use std::thread;
174    ///
175    /// let builder = thread::Builder::new();
176    ///
177    /// let handler = builder.spawn(|| {
178    ///     // thread code
179    /// }).unwrap();
180    ///
181    /// handler.join().unwrap();
182    /// ```
183    ///
184    /// [`thread::spawn`]: super::spawn
185    /// [`spawn`]: super::spawn
186    #[stable(feature = "rust1", since = "1.0.0")]
187    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
188    pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
189    where
190        F: FnOnce() -> T,
191        F: Send + 'static,
192        T: Send + 'static,
193    {
194        unsafe { self.spawn_unchecked(f) }
195    }
196
197    /// Spawns a new thread without any lifetime restrictions by taking ownership
198    /// of the `Builder`, and returns an [`io::Result`] to its [`JoinHandle`].
199    ///
200    /// The spawned thread may outlive the caller (unless the caller thread
201    /// is the main thread; the whole process is terminated when the main
202    /// thread finishes). The join handle can be used to block on
203    /// termination of the spawned thread, including recovering its panics.
204    ///
205    /// This method is identical to [`thread::Builder::spawn`][`Builder::spawn`],
206    /// except for the relaxed lifetime bounds, which render it unsafe.
207    /// For a more complete documentation see [`thread::spawn`].
208    ///
209    /// # Errors
210    ///
211    /// Unlike the [`spawn`] free function, this method yields an
212    /// [`io::Result`] to capture any failure to create the thread at
213    /// the OS level.
214    ///
215    /// # Panics
216    ///
217    /// Panics if a thread name was set and it contained null bytes.
218    ///
219    /// # Safety
220    ///
221    /// The caller has to ensure that the spawned thread does not outlive any
222    /// references in the supplied thread closure and its return type.
223    /// This can be guaranteed in two ways:
224    ///
225    /// - ensure that [`join`][`JoinHandle::join`] is called before any referenced
226    /// data is dropped
227    /// - use only types with `'static` lifetime bounds, i.e., those with no or only
228    /// `'static` references (both [`thread::Builder::spawn`][`Builder::spawn`]
229    /// and [`thread::spawn`] enforce this property statically)
230    ///
231    /// # Examples
232    ///
233    /// ```
234    /// use std::thread;
235    ///
236    /// let builder = thread::Builder::new();
237    ///
238    /// let x = 1;
239    /// let thread_x = &x;
240    ///
241    /// let handler = unsafe {
242    ///     builder.spawn_unchecked(move || {
243    ///         println!("x = {}", *thread_x);
244    ///     }).unwrap()
245    /// };
246    ///
247    /// // caller has to ensure `join()` is called, otherwise
248    /// // it is possible to access freed memory if `x` gets
249    /// // dropped before the thread closure is executed!
250    /// handler.join().unwrap();
251    /// ```
252    ///
253    /// [`io::Result`]: crate::io::Result
254    /// [`thread::spawn`]: super::spawn
255    /// [`spawn`]: super::spawn
256    #[stable(feature = "thread_spawn_unchecked", since = "1.82.0")]
257    #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
258    pub unsafe fn spawn_unchecked<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
259    where
260        F: FnOnce() -> T,
261        F: Send,
262        T: Send,
263    {
264        let Builder { name, stack_size, no_hooks } = self;
265        Ok(JoinHandle(unsafe { spawn_unchecked(name, stack_size, no_hooks, None, f) }?))
266    }
267}