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