• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use crate::task::JoinHandle;
2 
3 use std::future::Future;
4 
5 cfg_rt! {
6     /// Spawns a new asynchronous task, returning a
7     /// [`JoinHandle`](super::JoinHandle) for it.
8     ///
9     /// The provided future will start running in the background immediately
10     /// when `spawn` is called, even if you don't await the returned
11     /// `JoinHandle`.
12     ///
13     /// Spawning a task enables the task to execute concurrently to other tasks. The
14     /// spawned task may execute on the current thread, or it may be sent to a
15     /// different thread to be executed. The specifics depend on the current
16     /// [`Runtime`](crate::runtime::Runtime) configuration.
17     ///
18     /// It is guaranteed that spawn will not synchronously poll the task being spawned.
19     /// This means that calling spawn while holding a lock does not pose a risk of
20     /// deadlocking with the spawned task.
21     ///
22     /// There is no guarantee that a spawned task will execute to completion.
23     /// When a runtime is shutdown, all outstanding tasks are dropped,
24     /// regardless of the lifecycle of that task.
25     ///
26     /// This function must be called from the context of a Tokio runtime. Tasks running on
27     /// the Tokio runtime are always inside its context, but you can also enter the context
28     /// using the [`Runtime::enter`](crate::runtime::Runtime::enter()) method.
29     ///
30     /// # Examples
31     ///
32     /// In this example, a server is started and `spawn` is used to start a new task
33     /// that processes each received connection.
34     ///
35     /// ```no_run
36     /// use tokio::net::{TcpListener, TcpStream};
37     ///
38     /// use std::io;
39     ///
40     /// async fn process(socket: TcpStream) {
41     ///     // ...
42     /// # drop(socket);
43     /// }
44     ///
45     /// #[tokio::main]
46     /// async fn main() -> io::Result<()> {
47     ///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
48     ///
49     ///     loop {
50     ///         let (socket, _) = listener.accept().await?;
51     ///
52     ///         tokio::spawn(async move {
53     ///             // Process each socket concurrently.
54     ///             process(socket).await
55     ///         });
56     ///     }
57     /// }
58     /// ```
59     ///
60     /// To run multiple tasks in parallel and receive their results, join
61     /// handles can be stored in a vector.
62     /// ```
63     /// # #[tokio::main(flavor = "current_thread")] async fn main() {
64     /// async fn my_background_op(id: i32) -> String {
65     ///     let s = format!("Starting background task {}.", id);
66     ///     println!("{}", s);
67     ///     s
68     /// }
69     ///
70     /// let ops = vec![1, 2, 3];
71     /// let mut tasks = Vec::with_capacity(ops.len());
72     /// for op in ops {
73     ///     // This call will make them start running in the background
74     ///     // immediately.
75     ///     tasks.push(tokio::spawn(my_background_op(op)));
76     /// }
77     ///
78     /// let mut outputs = Vec::with_capacity(tasks.len());
79     /// for task in tasks {
80     ///     outputs.push(task.await.unwrap());
81     /// }
82     /// println!("{:?}", outputs);
83     /// # }
84     /// ```
85     /// This example pushes the tasks to `outputs` in the order they were
86     /// started in. If you do not care about the ordering of the outputs, then
87     /// you can also use a [`JoinSet`].
88     ///
89     /// [`JoinSet`]: struct@crate::task::JoinSet
90     ///
91     /// # Panics
92     ///
93     /// Panics if called from **outside** of the Tokio runtime.
94     ///
95     /// # Using `!Send` values from a task
96     ///
97     /// The task supplied to `spawn` must implement `Send`. However, it is
98     /// possible to **use** `!Send` values from the task as long as they only
99     /// exist between calls to `.await`.
100     ///
101     /// For example, this will work:
102     ///
103     /// ```
104     /// use tokio::task;
105     ///
106     /// use std::rc::Rc;
107     ///
108     /// fn use_rc(rc: Rc<()>) {
109     ///     // Do stuff w/ rc
110     /// # drop(rc);
111     /// }
112     ///
113     /// #[tokio::main]
114     /// async fn main() {
115     ///     tokio::spawn(async {
116     ///         // Force the `Rc` to stay in a scope with no `.await`
117     ///         {
118     ///             let rc = Rc::new(());
119     ///             use_rc(rc.clone());
120     ///         }
121     ///
122     ///         task::yield_now().await;
123     ///     }).await.unwrap();
124     /// }
125     /// ```
126     ///
127     /// This will **not** work:
128     ///
129     /// ```compile_fail
130     /// use tokio::task;
131     ///
132     /// use std::rc::Rc;
133     ///
134     /// fn use_rc(rc: Rc<()>) {
135     ///     // Do stuff w/ rc
136     /// # drop(rc);
137     /// }
138     ///
139     /// #[tokio::main]
140     /// async fn main() {
141     ///     tokio::spawn(async {
142     ///         let rc = Rc::new(());
143     ///
144     ///         task::yield_now().await;
145     ///
146     ///         use_rc(rc.clone());
147     ///     }).await.unwrap();
148     /// }
149     /// ```
150     ///
151     /// Holding on to a `!Send` value across calls to `.await` will result in
152     /// an unfriendly compile error message similar to:
153     ///
154     /// ```text
155     /// `[... some type ...]` cannot be sent between threads safely
156     /// ```
157     ///
158     /// or:
159     ///
160     /// ```text
161     /// error[E0391]: cycle detected when processing `main`
162     /// ```
163     #[track_caller]
164     pub fn spawn<T>(future: T) -> JoinHandle<T::Output>
165     where
166         T: Future + Send + 'static,
167         T::Output: Send + 'static,
168     {
169         // preventing stack overflows on debug mode, by quickly sending the
170         // task to the heap.
171         if cfg!(debug_assertions) && std::mem::size_of::<T>() > 2048 {
172             spawn_inner(Box::pin(future), None)
173         } else {
174             spawn_inner(future, None)
175         }
176     }
177 
178     #[track_caller]
179     pub(super) fn spawn_inner<T>(future: T, name: Option<&str>) -> JoinHandle<T::Output>
180     where
181         T: Future + Send + 'static,
182         T::Output: Send + 'static,
183     {
184         use crate::runtime::{context, task};
185 
186         #[cfg(all(
187             tokio_unstable,
188             tokio_taskdump,
189             feature = "rt",
190             target_os = "linux",
191             any(
192                 target_arch = "aarch64",
193                 target_arch = "x86",
194                 target_arch = "x86_64"
195             )
196         ))]
197         let future = task::trace::Trace::root(future);
198         let id = task::Id::next();
199         let task = crate::util::trace::task(future, "task", name, id.as_u64());
200 
201         match context::with_current(|handle| handle.spawn(task, id)) {
202             Ok(join_handle) => join_handle,
203             Err(e) => panic!("{}", e),
204         }
205     }
206 }
207