async_thread/lib.rs
1//! This crate provides an API identical to `std::thread`. However, `JoinHandle::join` is an `async
2//! fn`.
3//! ```
4//! let handle = crate::spawn(|| 5usize);
5//! assert_eq!(handle.join().await.map_err(drop), Ok(5));
6//! ```
7
8use futures_channel::oneshot;
9use std::any::Any;
10use std::io;
11use std::panic::{catch_unwind, AssertUnwindSafe};
12use std::thread as sync;
13
14/// An owned permission to join on a thread (block on its termination).
15///
16/// A `JoinHandle` *detaches* the associated thread when it is dropped, which
17/// means that there is no longer any handle to thread and no way to `join`
18/// on it.
19///
20/// Due to platform restrictions, it is not possible to `Clone` this
21/// handle: the ability to join a thread is a uniquely-owned permission.
22///
23/// This `struct` is created by the `thread::spawn` function and the
24/// `thread::Builder::spawn` method.
25///
26/// # Examples
27///
28/// Creation from `thread::spawn`:
29///
30/// ```
31/// let join_handle: async_thread::JoinHandle<_> = async_thread::spawn(|| {
32/// // some work here
33/// });
34/// ```
35///
36/// Creation from `thread::Builder::spawn`:
37///
38/// ```
39/// let builder = async_thread::Builder::new();
40///
41/// let join_handle: async_thread::JoinHandle<_> = builder.spawn(|| {
42/// // some work here
43/// }).unwrap();
44/// ```
45///
46/// Child being detached and outliving its parent:
47///
48/// ```no_run
49/// use std::time::Duration;
50///
51/// let original_thread = async_thread::spawn(|| {
52/// let _detached_thread = async_thread::spawn(|| {
53/// // Here we sleep to make sure that the first thread returns before.
54/// thread::sleep(Duration::from_millis(10));
55/// // This will be called, even though the JoinHandle is dropped.
56/// println!("♫ Still alive ♫");
57/// });
58/// });
59///
60/// original_thread.join().await.expect("The thread being joined has panicked");
61/// println!("Original thread is joined.");
62///
63/// // We make sure that the new thread has time to run, before the main
64/// // thread returns.
65///
66/// thread::sleep(Duration::from_millis(1000));
67/// ```
68#[derive(Debug)]
69pub struct JoinHandle<T> {
70 imp: sync::JoinHandle<()>,
71 chan: oneshot::Receiver<sync::Result<T>>,
72}
73
74impl<T> JoinHandle<T> {
75 /// Waits for the associated thread to finish.
76 ///
77 /// In terms of atomic memory orderings, the completion of the associated
78 /// thread synchronizes with this function returning. In other words, all
79 /// operations performed by that thread are ordered before all
80 /// operations that happen after `join` returns.
81 ///
82 /// If the child thread panics, `Err` is returned with the parameter given
83 /// to `panic`.
84 ///
85 /// # Panics
86 ///
87 /// This function may panic on some platforms if a thread attempts to join
88 /// itself or otherwise may create a deadlock with joining threads.
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// let builder = async_thread::Builder::new();
94 ///
95 /// let join_handle: async_thread::JoinHandle<_> = builder.spawn(|| {
96 /// // some work here
97 /// }).unwrap();
98 /// join_handle.join().await.expect("Couldn't join on the associated thread");
99 /// ```
100 pub async fn join(self) -> sync::Result<T> {
101 let ret = self.chan
102 .await
103 .map_err(|x| -> Box<dyn Any + Send + 'static> { Box::new(x) })
104 .and_then(|x| x);
105 let _ = self.imp.join(); // synchronize threads
106 ret
107 }
108
109 /// Extracts a handle to the underlying thread.
110 ///
111 /// # Examples
112 ///
113 /// ```
114 /// let builder = async_thread::Builder::new();
115 ///
116 /// let join_handle: async_thread::JoinHandle<_> = builder.spawn(|| {
117 /// // some work here
118 /// }).unwrap();
119 ///
120 /// let thread = join_handle.thread();
121 /// println!("thread id: {:?}", thread.id());
122 /// ```
123 pub fn thread(&self) -> &sync::Thread {
124 self.imp.thread()
125 }
126}
127
128/// Thread factory, which can be used in order to configure the properties of
129/// a new thread.
130///
131/// Methods can be chained on it in order to configure it.
132///
133/// The two configurations available are:
134///
135/// - `name`: specifies an associated name for the thread
136/// - `stack_size`: specifies the desired stack size for the thread
137///
138/// The `spawn` method will take ownership of the builder and create an
139/// `io::Result` to the thread handle with the given configuration.
140///
141/// The `thread::spawn` free function uses a `Builder` with default
142/// configuration and `unwrap`s its return value.
143///
144/// You may want to use `spawn` instead of `thread::spawn`, when you want
145/// to recover from a failure to launch a thread, indeed the free function will
146/// panic where the `Builder` method will return a `io::Result`.
147///
148/// # Examples
149///
150/// ```
151/// use std::thread;
152///
153/// let builder = thread::Builder::new();
154///
155/// let handler = builder.spawn(|| {
156/// // thread code
157/// }).unwrap();
158///
159/// handler.join().unwrap();
160/// ```
161#[derive(Debug)]
162pub struct Builder {
163 imp: sync::Builder,
164}
165
166impl Builder {
167 /// Generates the base configuration for spawning a thread, from which
168 /// configuration methods can be chained.
169 ///
170 /// # Examples
171 ///
172 /// ```
173 /// let builder = async_thread::Builder::new()
174 /// .name("foo".into())
175 /// .stack_size(32 * 1024);
176 ///
177 /// let handler = builder.spawn(|| {
178 /// // thread code
179 /// }).unwrap();
180 ///
181 /// handler.join().await.unwrap();
182 /// ```
183 pub fn new() -> Self {
184 Self {
185 imp: sync::Builder::new(),
186 }
187 }
188
189 /// Names the thread-to-be. Currently the name is used for identification
190 /// only in panic messages.
191 ///
192 /// The name must not contain null bytes (`\0`).
193 ///
194 /// For more information about named threads, see
195 /// the std::thread documentation.
196 ///
197 /// # Examples
198 ///
199 /// ```
200 /// let builder = async_thread::Builder::new()
201 /// .name("foo".into());
202 ///
203 /// let handler = builder.spawn(|| {
204 /// assert_eq!(thread::current().name(), Some("foo"))
205 /// }).unwrap();
206 ///
207 /// handler.join().await.unwrap();
208 /// ```
209 pub fn name(self, name: String) -> Self {
210 Self {
211 imp: self.imp.name(name),
212 }
213 }
214
215 /// Sets the size of the stack (in bytes) for the new thread.
216 ///
217 /// The actual stack size may be greater than this value if
218 /// the platform specifies a minimal stack size.
219 ///
220 /// For more information about the stack size for threads, see
221 /// the std::thread documentation.
222 ///
223 /// # Examples
224 ///
225 /// ```
226 /// let builder = async_thread::Builder::new().stack_size(32 * 1024);
227 /// ```
228 pub fn stack_size(self, size: usize) -> Self {
229 Self {
230 imp: self.imp.stack_size(size),
231 }
232 }
233
234 /// Spawns a new thread by taking ownership of the `Builder`, and returns an
235 /// `io::Result` to its `JoinHandle`.
236 ///
237 /// The spawned thread may outlive the caller (unless the caller thread
238 /// is the main thread; the whole process is terminated when the main
239 /// thread finishes). The join handle can be used to block on
240 /// termination of the child thread, including recovering its panics.
241 ///
242 /// For a more complete documentation see `async_thread::spawn`.
243 ///
244 /// # Errors
245 ///
246 /// Unlike the `spawn` free function, this method yields an
247 /// `io::Result` to capture any failure to create the thread at
248 /// the OS level.
249 ///
250 /// # Panics
251 ///
252 /// Panics if a thread name was set and it contained null bytes.
253 ///
254 /// # Examples
255 ///
256 /// ```
257 /// let builder = async_thread::Builder::new();
258 ///
259 /// let handler = builder.spawn(|| {
260 /// // thread code
261 /// }).unwrap();
262 ///
263 /// handler.join().await.unwrap();
264 /// ```
265 pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>>
266 where
267 F: FnOnce() -> T,
268 F: Send + 'static,
269 T: Send + 'static,
270 {
271 let (send, recv) = oneshot::channel();
272 let handle = self.imp.spawn(move || {
273 let _ = send.send(catch_unwind(AssertUnwindSafe(f)));
274 })?;
275
276 Ok(JoinHandle {
277 chan: recv,
278 imp: handle,
279 })
280 }
281}
282
283/// Spawns a new thread, returning a `JoinHandle` for it.
284///
285/// The join handle will implicitly *detach* the child thread upon being
286/// dropped. In this case, the child thread may outlive the parent (unless
287/// the parent thread is the main thread; the whole process is terminated when
288/// the main thread finishes). Additionally, the join handle provides a `join`
289/// method that can be used to join the child thread. If the child thread
290/// panics, `join` will return an `Err` containing the argument given to
291/// `panic`.
292///
293/// This will create a thread using default parameters of `Builder`, if you
294/// want to specify the stack size or the name of the thread, use this API
295/// instead.
296///
297/// As you can see in the signature of `spawn` there are two constraints on
298/// both the closure given to `spawn` and its return value, let's explain them:
299///
300/// - The `'static` constraint means that the closure and its return value
301/// must have a lifetime of the whole program execution. The reason for this
302/// is that threads can `detach` and outlive the lifetime they have been
303/// created in.
304/// Indeed if the thread, and by extension its return value, can outlive their
305/// caller, we need to make sure that they will be valid afterwards, and since
306/// we *can't* know when it will return we need to have them valid as long as
307/// possible, that is until the end of the program, hence the `'static`
308/// lifetime.
309/// - The `Send` constraint is because the closure will need to be passed
310/// *by value* from the thread where it is spawned to the new thread. Its
311/// return value will need to be passed from the new thread to the thread
312/// where it is `join`ed.
313/// As a reminder, the `Send` marker trait expresses that it is safe to be
314/// passed from thread to thread. `Sync` expresses that it is safe to have a
315/// reference be passed from thread to thread.
316///
317/// # Panics
318///
319/// Panics if the OS fails to create a thread; use `Builder::spawn`
320/// to recover from such errors.
321///
322/// # Examples
323///
324/// Creating a thread.
325///
326/// ```
327/// let handler = async_thread::spawn(|| {
328/// // thread code
329/// });
330///
331/// handler.join().await.unwrap();
332/// ```
333///
334/// As mentioned in the std::thread documentation, threads are usually made to
335/// communicate using `channels`, here is how it usually looks.
336///
337/// This example also shows how to use `move`, in order to give ownership
338/// of values to a thread.
339///
340/// ```
341/// use std::sync::mpsc::channel;
342///
343/// let (tx, rx) = channel();
344///
345/// let sender = async_thread::spawn(move || {
346/// tx.send("Hello, thread".to_owned())
347/// .expect("Unable to send on channel");
348/// });
349///
350/// let receiver = async_thread::spawn(move || {
351/// let value = rx.recv().expect("Unable to receive from channel");
352/// println!("{}", value);
353/// });
354///
355/// sender.join().await.expect("The sender thread has panicked");
356/// receiver.join().await.expect("The receiver thread has panicked");
357/// ```
358///
359/// A thread can also return a value through its `JoinHandle`, you can use
360/// this to make asynchronous computations.
361///
362/// ```
363/// let computation = async_thread::spawn(|| {
364/// // Some expensive computation.
365/// 42
366/// });
367///
368/// let result = computation.join().await.unwrap();
369/// println!("{}", result);
370/// ```
371pub fn spawn<F, T>(f: F) -> JoinHandle<T>
372where
373 F: FnOnce() -> T,
374 F: Send + 'static,
375 T: Send + 'static,
376{
377 Builder::new().spawn(f).expect("failed to spawn thread")
378}
379
380#[cfg(test)]
381mod tests {
382 #[async_std::test]
383 async fn it_works() {
384 let handle = crate::spawn(|| 5usize);
385 assert_eq!(handle.join().await.map_err(drop), Ok(5));
386 }
387}