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}