]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch16-01-threads.md
New upstream version 1.60.0+dfsg1
[rustc.git] / src / doc / book / src / ch16-01-threads.md
1 ## Using Threads to Run Code Simultaneously
2
3 In most current operating systems, an executed program’s code is run in a
4 *process*, and the operating system manages multiple processes at once. Within
5 your program, you can also have independent parts that run simultaneously. The
6 features that run these independent parts are called *threads*.
7
8 Splitting the computation in your program into multiple threads can improve
9 performance because the program does multiple tasks at the same time, but it
10 also adds complexity. Because threads can run simultaneously, there’s no
11 inherent guarantee about the order in which parts of your code on different
12 threads will run. This can lead to problems, such as:
13
14 * Race conditions, where threads are accessing data or resources in an
15 inconsistent order
16 * Deadlocks, where two threads are waiting for each other to finish using a
17 resource the other thread has, preventing both threads from continuing
18 * Bugs that happen only in certain situations and are hard to reproduce and fix
19 reliably
20
21 Rust attempts to mitigate the negative effects of using threads, but
22 programming in a multithreaded context still takes careful thought and requires
23 a code structure that is different from that in programs running in a single
24 thread.
25
26 Programming languages implement threads in a few different ways. Many operating
27 systems provide an API for creating new threads. This model where a language
28 calls the operating system APIs to create threads is sometimes called *1:1*,
29 meaning one operating system thread per one language thread. The Rust standard
30 library only provides an implementation of 1:1 threading; there are crates that
31 implement other models of threading that make different tradeoffs.
32
33 ### Creating a New Thread with `spawn`
34
35 To create a new thread, we call the `thread::spawn` function and pass it a
36 closure (we talked about closures in Chapter 13) containing the code we want to
37 run in the new thread. The example in Listing 16-1 prints some text from a main
38 thread and other text from a new thread:
39
40 <span class="filename">Filename: src/main.rs</span>
41
42 ```rust
43 {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-01/src/main.rs}}
44 ```
45
46 <span class="caption">Listing 16-1: Creating a new thread to print one thing
47 while the main thread prints something else</span>
48
49 Note that with this function, the new thread will be stopped when the main
50 thread ends, whether or not it has finished running. The output from this
51 program might be a little different every time, but it will look similar to the
52 following:
53
54 <!-- Not extracting output because changes to this output aren't significant;
55 the changes are likely to be due to the threads running differently rather than
56 changes in the compiler -->
57
58 ```text
59 hi number 1 from the main thread!
60 hi number 1 from the spawned thread!
61 hi number 2 from the main thread!
62 hi number 2 from the spawned thread!
63 hi number 3 from the main thread!
64 hi number 3 from the spawned thread!
65 hi number 4 from the main thread!
66 hi number 4 from the spawned thread!
67 hi number 5 from the spawned thread!
68 ```
69
70 The calls to `thread::sleep` force a thread to stop its execution for a short
71 duration, allowing a different thread to run. The threads will probably take
72 turns, but that isn’t guaranteed: it depends on how your operating system
73 schedules the threads. In this run, the main thread printed first, even though
74 the print statement from the spawned thread appears first in the code. And even
75 though we told the spawned thread to print until `i` is 9, it only got to 5
76 before the main thread shut down.
77
78 If you run this code and only see output from the main thread, or don’t see any
79 overlap, try increasing the numbers in the ranges to create more opportunities
80 for the operating system to switch between the threads.
81
82 ### Waiting for All Threads to Finish Using `join` Handles
83
84 The code in Listing 16-1 not only stops the spawned thread prematurely most of
85 the time due to the main thread ending, but also can’t guarantee that the
86 spawned thread will get to run at all. The reason is that there is no guarantee
87 on the order in which threads run!
88
89 We can fix the problem of the spawned thread not getting to run, or not getting
90 to run completely, by saving the return value of `thread::spawn` in a variable.
91 The return type of `thread::spawn` is `JoinHandle`. A `JoinHandle` is an owned
92 value that, when we call the `join` method on it, will wait for its thread to
93 finish. Listing 16-2 shows how to use the `JoinHandle` of the thread we created
94 in Listing 16-1 and call `join` to make sure the spawned thread finishes before
95 `main` exits:
96
97 <span class="filename">Filename: src/main.rs</span>
98
99 ```rust
100 {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-02/src/main.rs}}
101 ```
102
103 <span class="caption">Listing 16-2: Saving a `JoinHandle` from `thread::spawn`
104 to guarantee the thread is run to completion</span>
105
106 Calling `join` on the handle blocks the thread currently running until the
107 thread represented by the handle terminates. *Blocking* a thread means that
108 thread is prevented from performing work or exiting. Because we’ve put the call
109 to `join` after the main thread’s `for` loop, running Listing 16-2 should
110 produce output similar to this:
111
112 <!-- Not extracting output because changes to this output aren't significant;
113 the changes are likely to be due to the threads running differently rather than
114 changes in the compiler -->
115
116 ```text
117 hi number 1 from the main thread!
118 hi number 2 from the main thread!
119 hi number 1 from the spawned thread!
120 hi number 3 from the main thread!
121 hi number 2 from the spawned thread!
122 hi number 4 from the main thread!
123 hi number 3 from the spawned thread!
124 hi number 4 from the spawned thread!
125 hi number 5 from the spawned thread!
126 hi number 6 from the spawned thread!
127 hi number 7 from the spawned thread!
128 hi number 8 from the spawned thread!
129 hi number 9 from the spawned thread!
130 ```
131
132 The two threads continue alternating, but the main thread waits because of the
133 call to `handle.join()` and does not end until the spawned thread is finished.
134
135 But let’s see what happens when we instead move `handle.join()` before the
136 `for` loop in `main`, like this:
137
138 <span class="filename">Filename: src/main.rs</span>
139
140 ```rust
141 {{#rustdoc_include ../listings/ch16-fearless-concurrency/no-listing-01-join-too-early/src/main.rs}}
142 ```
143
144 The main thread will wait for the spawned thread to finish and then run its
145 `for` loop, so the output won’t be interleaved anymore, as shown here:
146
147 <!-- Not extracting output because changes to this output aren't significant;
148 the changes are likely to be due to the threads running differently rather than
149 changes in the compiler -->
150
151 ```text
152 hi number 1 from the spawned thread!
153 hi number 2 from the spawned thread!
154 hi number 3 from the spawned thread!
155 hi number 4 from the spawned thread!
156 hi number 5 from the spawned thread!
157 hi number 6 from the spawned thread!
158 hi number 7 from the spawned thread!
159 hi number 8 from the spawned thread!
160 hi number 9 from the spawned thread!
161 hi number 1 from the main thread!
162 hi number 2 from the main thread!
163 hi number 3 from the main thread!
164 hi number 4 from the main thread!
165 ```
166
167 Small details, such as where `join` is called, can affect whether or not your
168 threads run at the same time.
169
170 ### Using `move` Closures with Threads
171
172 The `move` keyword is often used with closures passed to `thread::spawn`
173 because the closure will then take ownership of the values it uses from the
174 environment, thus transferring ownership of those values from one thread to
175 another. In the [“Capturing the Environment with Closures”][capture]<!-- ignore
176 --> section of Chapter 13, we discussed `move` in the context of closures. Now,
177 we’ll concentrate more on the interaction between `move` and `thread::spawn`
178
179 Notice in Listing 16-1 that the closure we pass to `thread::spawn` takes no
180 arguments: we’re not using any data from the main thread in the spawned
181 thread’s code. To use data from the main thread in the spawned thread, the
182 spawned thread’s closure must capture the values it needs. Listing 16-3 shows
183 an attempt to create a vector in the main thread and use it in the spawned
184 thread. However, this won’t yet work, as you’ll see in a moment.
185
186 <span class="filename">Filename: src/main.rs</span>
187
188 ```rust,ignore,does_not_compile
189 {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-03/src/main.rs}}
190 ```
191
192 <span class="caption">Listing 16-3: Attempting to use a vector created by the
193 main thread in another thread</span>
194
195 The closure uses `v`, so it will capture `v` and make it part of the closure’s
196 environment. Because `thread::spawn` runs this closure in a new thread, we
197 should be able to access `v` inside that new thread. But when we compile this
198 example, we get the following error:
199
200 ```console
201 {{#include ../listings/ch16-fearless-concurrency/listing-16-03/output.txt}}
202 ```
203
204 Rust *infers* how to capture `v`, and because `println!` only needs a reference
205 to `v`, the closure tries to borrow `v`. However, there’s a problem: Rust can’t
206 tell how long the spawned thread will run, so it doesn’t know if the reference
207 to `v` will always be valid.
208
209 Listing 16-4 provides a scenario that’s more likely to have a reference to `v`
210 that won’t be valid:
211
212 <span class="filename">Filename: src/main.rs</span>
213
214 ```rust,ignore,does_not_compile
215 {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-04/src/main.rs}}
216 ```
217
218 <span class="caption">Listing 16-4: A thread with a closure that attempts to
219 capture a reference to `v` from a main thread that drops `v`</span>
220
221 If we were allowed to run this code, there’s a possibility the spawned thread
222 would be immediately put in the background without running at all. The spawned
223 thread has a reference to `v` inside, but the main thread immediately drops
224 `v`, using the `drop` function we discussed in Chapter 15. Then, when the
225 spawned thread starts to execute, `v` is no longer valid, so a reference to it
226 is also invalid. Oh no!
227
228 To fix the compiler error in Listing 16-3, we can use the error message’s
229 advice:
230
231 <!-- manual-regeneration
232 after automatic regeneration, look at listings/ch16-fearless-concurrency/listing-16-03/output.txt and copy the relevant part
233 -->
234
235 ```text
236 help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword
237 |
238 6 | let handle = thread::spawn(move || {
239 | ++++
240 ```
241
242 By adding the `move` keyword before the closure, we force the closure to take
243 ownership of the values it’s using rather than allowing Rust to infer that it
244 should borrow the values. The modification to Listing 16-3 shown in Listing
245 16-5 will compile and run as we intend:
246
247 <span class="filename">Filename: src/main.rs</span>
248
249 ```rust
250 {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-05/src/main.rs}}
251 ```
252
253 <span class="caption">Listing 16-5: Using the `move` keyword to force a closure
254 to take ownership of the values it uses</span>
255
256 What would happen to the code in Listing 16-4 where the main thread called
257 `drop` if we use a `move` closure? Would `move` fix that case? Unfortunately,
258 no; we would get a different error because what Listing 16-4 is trying to do
259 isn’t allowed for a different reason. If we added `move` to the closure, we
260 would move `v` into the closure’s environment, and we could no longer call
261 `drop` on it in the main thread. We would get this compiler error instead:
262
263 ```console
264 {{#include ../listings/ch16-fearless-concurrency/output-only-01-move-drop/output.txt}}
265 ```
266
267 Rust’s ownership rules have saved us again! We got an error from the code in
268 Listing 16-3 because Rust was being conservative and only borrowing `v` for the
269 thread, which meant the main thread could theoretically invalidate the spawned
270 thread’s reference. By telling Rust to move ownership of `v` to the spawned
271 thread, we’re guaranteeing Rust that the main thread won’t use `v` anymore. If
272 we change Listing 16-4 in the same way, we’re then violating the ownership
273 rules when we try to use `v` in the main thread. The `move` keyword overrides
274 Rust’s conservative default of borrowing; it doesn’t let us violate the
275 ownership rules.
276
277 With a basic understanding of threads and the thread API, let’s look at what we
278 can *do* with threads.
279
280 [capture]: ch13-01-closures.html#capturing-the-environment-with-closures