broker_tokio/task/
spawn.rs

1use crate::runtime;
2use crate::task::JoinHandle;
3
4use std::future::Future;
5
6doc_rt_core! {
7    /// Spawns a new asynchronous task, returning a
8    /// [`JoinHandle`](super::JoinHandle) for it.
9    ///
10    /// Spawning a task enables the task to execute concurrently to other tasks. The
11    /// spawned task may execute on the current thread, or it may be sent to a
12    /// different thread to be executed. The specifics depend on the current
13    /// [`Runtime`](crate::runtime::Runtime) configuration.
14    ///
15    /// There is no guarantee that a spawned task will execute to completion.
16    /// When a runtime is shutdown, all outstanding tasks are dropped,
17    /// regardless of the lifecycle of that task.
18    ///
19    /// # Examples
20    ///
21    /// In this example, a server is started and `spawn` is used to start a new task
22    /// that processes each received connection.
23    ///
24    /// ```no_run
25    /// use tokio::net::{TcpListener, TcpStream};
26    ///
27    /// use std::io;
28    ///
29    /// async fn process(socket: TcpStream) {
30    ///     // ...
31    /// # drop(socket);
32    /// }
33    ///
34    /// #[tokio::main]
35    /// async fn main() -> io::Result<()> {
36    ///     let mut listener = TcpListener::bind("127.0.0.1:8080").await?;
37    ///
38    ///     loop {
39    ///         let (socket, _) = listener.accept().await?;
40    ///
41    ///         tokio::spawn(async move {
42    ///             // Process each socket concurrently.
43    ///             process(socket).await
44    ///         });
45    ///     }
46    /// }
47    /// ```
48    ///
49    /// # Panics
50    ///
51    /// Panics if called from **outside** of the Tokio runtime.
52    ///
53    /// # Using `!Send` values from a task
54    ///
55    /// The task supplied to `spawn` must implement `Send`. However, it is
56    /// possible to **use** `!Send` values from the task as long as they only
57    /// exist between calls to `.await`.
58    ///
59    /// For example, this will work:
60    ///
61    /// ```
62    /// use tokio::task;
63    ///
64    /// use std::rc::Rc;
65    ///
66    /// fn use_rc(rc: Rc<()>) {
67    ///     // Do stuff w/ rc
68    /// # drop(rc);
69    /// }
70    ///
71    /// #[tokio::main]
72    /// async fn main() {
73    ///     tokio::spawn(async {
74    ///         // Force the `Rc` to stay in a scope with no `.await`
75    ///         {
76    ///             let rc = Rc::new(());
77    ///             use_rc(rc.clone());
78    ///         }
79    ///
80    ///         task::yield_now().await;
81    ///     }).await.unwrap();
82    /// }
83    /// ```
84    ///
85    /// This will **not** work:
86    ///
87    /// ```compile_fail
88    /// use tokio::task;
89    ///
90    /// use std::rc::Rc;
91    ///
92    /// fn use_rc(rc: Rc<()>) {
93    ///     // Do stuff w/ rc
94    /// # drop(rc);
95    /// }
96    ///
97    /// #[tokio::main]
98    /// async fn main() {
99    ///     tokio::spawn(async {
100    ///         let rc = Rc::new(());
101    ///
102    ///         task::yield_now().await;
103    ///
104    ///         use_rc(rc.clone());
105    ///     }).await.unwrap();
106    /// }
107    /// ```
108    ///
109    /// Holding on to a `!Send` value across calls to `.await` will result in
110    /// an unfriendly compile error message similar to:
111    ///
112    /// ```text
113    /// `[... some type ...]` cannot be sent between threads safely
114    /// ```
115    ///
116    /// or:
117    ///
118    /// ```text
119    /// error[E0391]: cycle detected when processing `main`
120    /// ```
121    pub fn spawn<T>(task: T) -> JoinHandle<T::Output>
122    where
123        T: Future + Send + 'static,
124        T::Output: Send + 'static,
125    {
126        let spawn_handle = runtime::context::spawn_handle()
127        .expect("must be called from the context of Tokio runtime configured with either `basic_scheduler` or `threaded_scheduler`");
128        spawn_handle.spawn(task)
129    }
130}