]> git.proxmox.com Git - rustc.git/blame - src/doc/trpl/concurrency.md
Imported Upstream version 1.0.0~beta.3
[rustc.git] / src / doc / trpl / concurrency.md
CommitLineData
85aaf69f
SL
1% Concurrency
2
3Concurrency and parallelism are incredibly important topics in computer
4science, and are also a hot topic in industry today. Computers are gaining more
5and more cores, yet many programmers aren't prepared to fully utilize them.
6
7Rust's memory safety features also apply to its concurrency story too. Even
8concurrent Rust programs must be memory safe, having no data races. Rust's type
9system is up to the task, and gives you powerful ways to reason about
10concurrent code at compile time.
11
12Before we talk about the concurrency features that come with Rust, it's important
13to understand something: Rust is low-level enough that all of this is provided
14by the standard library, not by the language. This means that if you don't like
15some aspect of the way Rust handles concurrency, you can implement an alternative
16way of doing things. [mio](https://github.com/carllerche/mio) is a real-world
17example of this principle in action.
18
19## Background: `Send` and `Sync`
20
21Concurrency is difficult to reason about. In Rust, we have a strong, static
22type system to help us reason about our code. As such, Rust gives us two traits
23to help us make sense of code that can possibly be concurrent.
24
25### `Send`
26
27The first trait we're going to talk about is
28[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates
29to the compiler that something of this type is able to have ownership transferred
30safely between threads.
31
32This is important to enforce certain restrictions. For example, if we have a
33channel connecting two threads, we would want to be able to send some data
34down the channel and to the other thread. Therefore, we'd ensure that `Send` was
35implemented for that type.
36
37In the opposite way, if we were wrapping a library with FFI that isn't
38threadsafe, we wouldn't want to implement `Send`, and so the compiler will help
39us enforce that it can't leave the current thread.
40
41### `Sync`
42
c34b1796 43The second of these traits is called [`Sync`](../std/marker/trait.Sync.html).
85aaf69f
SL
44When a type `T` implements `Sync`, it indicates to the compiler that something
45of this type has no possibility of introducing memory unsafety when used from
46multiple threads concurrently.
47
48For example, sharing immutable data with an atomic reference count is
49threadsafe. Rust provides a type like this, `Arc<T>`, and it implements `Sync`,
c34b1796 50so it is safe to share between threads.
85aaf69f
SL
51
52These two traits allow you to use the type system to make strong guarantees
53about the properties of your code under concurrency. Before we demonstrate
54why, we need to learn how to create a concurrent Rust program in the first
55place!
56
57## Threads
58
9346a6ac 59Rust's standard library provides a library for threads, which allow you to
85aaf69f
SL
60run Rust code in parallel. Here's a basic example of using `std::thread`:
61
62```
63use std::thread;
64
65fn main() {
9346a6ac 66 thread::spawn(|| {
85aaf69f
SL
67 println!("Hello from a thread!");
68 });
69}
70```
71
9346a6ac
AL
72The `thread::spawn()` method accepts a closure, which is executed in a
73new thread. It returns a handle to the thread, that can be used to
74wait for the child thread to finish and extract its result:
85aaf69f
SL
75
76```
77use std::thread;
78
79fn main() {
9346a6ac
AL
80 let handle = thread::spawn(|| {
81 "Hello from a thread!"
85aaf69f
SL
82 });
83
9346a6ac 84 println!("{}", handle.join().unwrap());
85aaf69f
SL
85}
86```
87
85aaf69f
SL
88Many languages have the ability to execute threads, but it's wildly unsafe.
89There are entire books about how to prevent errors that occur from shared
90mutable state. Rust helps out with its type system here as well, by preventing
91data races at compile time. Let's talk about how you actually share things
92between threads.
93
94## Safe Shared Mutable State
95
96Due to Rust's type system, we have a concept that sounds like a lie: "safe
97shared mutable state." Many programmers agree that shared mutable state is
98very, very bad.
99
100Someone once said this:
101
102> Shared mutable state is the root of all evil. Most languages attempt to deal
103> with this problem through the 'mutable' part, but Rust deals with it by
104> solving the 'shared' part.
105
106The same [ownership system](ownership.html) that helps prevent using pointers
107incorrectly also helps rule out data races, one of the worst kinds of
108concurrency bugs.
109
110As an example, here is a Rust program that would have a data race in many
111languages. It will not compile:
112
113```ignore
114use std::thread;
85aaf69f
SL
115
116fn main() {
117 let mut data = vec![1u32, 2, 3];
118
119 for i in 0..2 {
120 thread::spawn(move || {
121 data[i] += 1;
122 });
123 }
124
9346a6ac 125 thread::sleep_ms(50);
85aaf69f
SL
126}
127```
128
129This gives us an error:
130
131```text
9346a6ac 1328:17 error: capture of moved value: `data`
85aaf69f
SL
133 data[i] += 1;
134 ^~~~
135```
136
137In this case, we know that our code _should_ be safe, but Rust isn't sure. And
138it's actually not safe: if we had a reference to `data` in each thread, and the
139thread takes ownership of the reference, we have three owners! That's bad. We
140can fix this by using the `Arc<T>` type, which is an atomic reference counted
141pointer. The 'atomic' part means that it's safe to share across threads.
142
143`Arc<T>` assumes one more property about its contents to ensure that it is safe
144to share across threads: it assumes its contents are `Sync`. But in our
145case, we want to be able to mutate the value. We need a type that can ensure
146only one person at a time can mutate what's inside. For that, we can use the
147`Mutex<T>` type. Here's the second version of our code. It still doesn't work,
148but for a different reason:
149
150```ignore
151use std::thread;
85aaf69f
SL
152use std::sync::Mutex;
153
154fn main() {
155 let mut data = Mutex::new(vec![1u32, 2, 3]);
156
157 for i in 0..2 {
158 let data = data.lock().unwrap();
159 thread::spawn(move || {
160 data[i] += 1;
161 });
162 }
163
9346a6ac 164 thread::sleep_ms(50);
85aaf69f
SL
165}
166```
167
168Here's the error:
169
170```text
9346a6ac 171<anon>:9:9: 9:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
c34b1796 172<anon>:11 thread::spawn(move || {
85aaf69f 173 ^~~~~~~~~~~~~
9346a6ac 174<anon>:9:9: 9:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
c34b1796 175<anon>:11 thread::spawn(move || {
85aaf69f
SL
176 ^~~~~~~~~~~~~
177```
178
179You see, [`Mutex`](std/sync/struct.Mutex.html) has a
180[`lock`](http://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html#method.lock)
181method which has this signature:
182
183```ignore
184fn lock(&self) -> LockResult<MutexGuard<T>>
185```
186
c34b1796
AL
187Because `Send` is not implemented for `MutexGuard<T>`, we can't transfer the
188guard across thread boundaries, which gives us our error.
85aaf69f
SL
189
190We can use `Arc<T>` to fix this. Here's the working version:
191
192```
193use std::sync::{Arc, Mutex};
194use std::thread;
85aaf69f
SL
195
196fn main() {
197 let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
198
199 for i in 0..2 {
200 let data = data.clone();
201 thread::spawn(move || {
202 let mut data = data.lock().unwrap();
203 data[i] += 1;
204 });
205 }
206
9346a6ac 207 thread::sleep_ms(50);
85aaf69f
SL
208}
209```
210
211We now call `clone()` on our `Arc`, which increases the internal count. This
212handle is then moved into the new thread. Let's examine the body of the
213thread more closely:
214
9346a6ac 215```rust
85aaf69f
SL
216# use std::sync::{Arc, Mutex};
217# use std::thread;
85aaf69f
SL
218# fn main() {
219# let data = Arc::new(Mutex::new(vec![1u32, 2, 3]));
220# for i in 0..2 {
221# let data = data.clone();
222thread::spawn(move || {
223 let mut data = data.lock().unwrap();
224 data[i] += 1;
225});
226# }
9346a6ac 227# thread::sleep_ms(50);
85aaf69f
SL
228# }
229```
230
231First, we call `lock()`, which acquires the mutex's lock. Because this may fail,
232it returns an `Result<T, E>`, and because this is just an example, we `unwrap()`
233it to get a reference to the data. Real code would have more robust error handling
234here. We're then free to mutate it, since we have the lock.
235
c34b1796
AL
236Lastly, while the threads are running, we wait on a short timer. But
237this is not ideal: we may have picked a reasonable amount of time to
238wait but it's more likely we'll either be waiting longer than
239necessary or not long enough, depending on just how much time the
240threads actually take to finish computing when the program runs.
85aaf69f 241
c34b1796
AL
242A more precise alternative to the timer would be to use one of the
243mechanisms provided by the Rust standard library for synchronizing
244threads with each other. Let's talk about one of them: channels.
85aaf69f
SL
245
246## Channels
247
248Here's a version of our code that uses channels for synchronization, rather
249than waiting for a specific time:
250
251```
252use std::sync::{Arc, Mutex};
253use std::thread;
254use std::sync::mpsc;
255
256fn main() {
257 let data = Arc::new(Mutex::new(0u32));
258
259 let (tx, rx) = mpsc::channel();
260
261 for _ in 0..10 {
262 let (data, tx) = (data.clone(), tx.clone());
263
264 thread::spawn(move || {
265 let mut data = data.lock().unwrap();
266 *data += 1;
267
268 tx.send(());
269 });
270 }
271
272 for _ in 0..10 {
273 rx.recv();
274 }
275}
276```
277
278We use the `mpsc::channel()` method to construct a new channel. We just `send`
279a simple `()` down the channel, and then wait for ten of them to come back.
280
281While this channel is just sending a generic signal, we can send any data that
282is `Send` over the channel!
283
284```
85aaf69f
SL
285use std::thread;
286use std::sync::mpsc;
287
288fn main() {
289 let (tx, rx) = mpsc::channel();
290
291 for _ in 0..10 {
292 let tx = tx.clone();
293
294 thread::spawn(move || {
295 let answer = 42u32;
296
297 tx.send(answer);
298 });
299 }
300
c34b1796 301 rx.recv().ok().expect("Could not receive answer");
85aaf69f
SL
302}
303```
304
305A `u32` is `Send` because we can make a copy. So we create a thread, ask it to calculate
306the answer, and then it `send()`s us the answer over the channel.
307
308
309## Panics
310
311A `panic!` will crash the currently executing thread. You can use Rust's
312threads as a simple isolation mechanism:
313
314```
315use std::thread;
316
317let result = thread::spawn(move || {
318 panic!("oops!");
319}).join();
320
321assert!(result.is_err());
322```
323
324Our `Thread` gives us a `Result` back, which allows us to check if the thread
325has panicked or not.