Skip to content

Commit ef07245

Browse files
authored
Merge pull request #1779 from vitorenesduarte/improved_compiler_output_16.3
Adapt content of Chapter 16.3 in order to be consistent with improved compiler message
2 parents 120e76a + 3b12d4d commit ef07245

File tree

1 file changed

+24
-115
lines changed

1 file changed

+24
-115
lines changed

src/ch16-03-shared-state.md

Lines changed: 24 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,9 @@ to change the inner `i32` to 6.
103103

104104
Now, let’s try to share a value between multiple threads using `Mutex<T>`.
105105
We’ll spin up 10 threads and have them each increment a counter value by 1, so
106-
the counter goes from 0 to 10. Note that the next few examples will have
107-
compiler errors, and we’ll use those errors to learn more about using
108-
`Mutex<T>` and how Rust helps us use it correctly. Listing 16-13 has our
109-
starting example:
106+
the counter goes from 0 to 10. The next example in Listing 16-13 will have
107+
a compiler error, and we’ll use that error to learn more about using
108+
`Mutex<T>` and how Rust helps us use it correctly.
110109

111110
<span class="filename">Filename: src/main.rs</span>
112111

@@ -154,110 +153,23 @@ program.
154153
We hinted that this example wouldn’t compile. Now let’s find out why!
155154

156155
```text
157-
error[E0382]: capture of moved value: `counter`
158-
--> src/main.rs:10:27
159-
|
160-
9 | let handle = thread::spawn(move || {
161-
| ------- value moved (into closure) here
162-
10 | let mut num = counter.lock().unwrap();
163-
| ^^^^^^^ value captured here after move
164-
|
165-
= note: move occurs because `counter` has type `std::sync::Mutex<i32>`,
166-
which does not implement the `Copy` trait
167-
168156
error[E0382]: use of moved value: `counter`
169-
--> src/main.rs:21:29
157+
--> src/main.rs:9:36
170158
|
171159
9 | let handle = thread::spawn(move || {
172-
| ------- value moved (into closure) here
173-
...
174-
21 | println!("Result: {}", *counter.lock().unwrap());
175-
| ^^^^^^^ value used here after move
176-
|
177-
= note: move occurs because `counter` has type `std::sync::Mutex<i32>`,
178-
which does not implement the `Copy` trait
179-
180-
error: aborting due to 2 previous errors
181-
```
182-
183-
The error message states that the `counter` value is moved into the closure and
184-
then captured when we call `lock`. That description sounds like what we wanted,
185-
but it’s not allowed!
186-
187-
Let’s figure this out by simplifying the program. Instead of making 10 threads
188-
in a `for` loop, let’s just make two threads without a loop and see what
189-
happens. Replace the first `for` loop in Listing 16-13 with this code instead:
190-
191-
```rust,ignore,does_not_compile
192-
use std::sync::Mutex;
193-
use std::thread;
194-
195-
fn main() {
196-
let counter = Mutex::new(0);
197-
let mut handles = vec![];
198-
199-
let handle = thread::spawn(move || {
200-
let mut num = counter.lock().unwrap();
201-
202-
*num += 1;
203-
});
204-
handles.push(handle);
205-
206-
let handle2 = thread::spawn(move || {
207-
let mut num2 = counter.lock().unwrap();
208-
209-
*num2 += 1;
210-
});
211-
handles.push(handle2);
212-
213-
for handle in handles {
214-
handle.join().unwrap();
215-
}
216-
217-
println!("Result: {}", *counter.lock().unwrap());
218-
}
219-
```
220-
221-
We make two threads and change the variable names used with the second thread
222-
to `handle2` and `num2`. When we run the code this time, compiling gives us the
223-
following:
224-
225-
```text
226-
error[E0382]: capture of moved value: `counter`
227-
--> src/main.rs:16:24
228-
|
229-
8 | let handle = thread::spawn(move || {
230-
| ------- value moved (into closure) here
231-
...
232-
16 | let mut num2 = counter.lock().unwrap();
233-
| ^^^^^^^ value captured here after move
234-
|
235-
= note: move occurs because `counter` has type `std::sync::Mutex<i32>`,
236-
which does not implement the `Copy` trait
237-
238-
error[E0382]: use of moved value: `counter`
239-
--> src/main.rs:26:29
240-
|
241-
8 | let handle = thread::spawn(move || {
242-
| ------- value moved (into closure) here
243-
...
244-
26 | println!("Result: {}", *counter.lock().unwrap());
245-
| ^^^^^^^ value used here after move
160+
| ^^^^^^^ value moved into closure here,
161+
in previous iteration of loop
162+
10 | let mut num = counter.lock().unwrap();
163+
| ------- use occurs due to use in closure
246164
|
247165
= note: move occurs because `counter` has type `std::sync::Mutex<i32>`,
248-
which does not implement the `Copy` trait
249-
250-
error: aborting due to 2 previous errors
166+
which does not implement the `Copy` trait
251167
```
252168

253-
Aha! The first error message indicates that `counter` is moved into the closure
254-
for the thread associated with `handle`. That move is preventing us from
255-
capturing `counter` when we try to call `lock` on it and store the result in
256-
`num2` in the second thread! So Rust is telling us that we can’t move ownership
257-
of `counter` into multiple threads. This was hard to see earlier because our
258-
threads were in a loop, and Rust can’t point to different threads in different
259-
iterations of the loop. Let’s fix the compiler error with a multiple-ownership
260-
method we discussed in Chapter 15.
169+
The error message states that the `counter` value was moved in the previous
170+
iteration of the loop. So Rust is telling us that we can’t move the ownership
171+
of lock `counter` into multiple threads. Let’s fix the compiler error with a
172+
multiple-ownership method we discussed in Chapter 15.
261173

262174
#### Multiple Ownership with Multiple Threads
263175

@@ -304,30 +216,27 @@ Once again, we compile and get... different errors! The compiler is teaching us
304216
a lot.
305217

306218
```text
307-
error[E0277]: the trait bound `std::rc::Rc<std::sync::Mutex<i32>>:
308-
std::marker::Send` is not satisfied in `[closure@src/main.rs:11:36:
309-
15:10 counter:std::rc::Rc<std::sync::Mutex<i32>>]`
219+
error[E0277]: `std::rc::Rc<std::sync::Mutex<i32>>` cannot be sent between threads safely
310220
--> src/main.rs:11:22
311221
|
312222
11 | let handle = thread::spawn(move || {
313223
| ^^^^^^^^^^^^^ `std::rc::Rc<std::sync::Mutex<i32>>`
314224
cannot be sent between threads safely
315225
|
316-
= help: within `[closure@src/main.rs:11:36: 15:10
317-
counter:std::rc::Rc<std::sync::Mutex<i32>>]`, the trait `std::marker::Send` is
318-
not implemented for `std::rc::Rc<std::sync::Mutex<i32>>`
226+
= help: within `[closure@src/main.rs:11:36: 14:10
227+
counter:std::rc::Rc<std::sync::Mutex<i32>>]`, the trait `std::marker::Send`
228+
is not implemented for `std::rc::Rc<std::sync::Mutex<i32>>`
319229
= note: required because it appears within the type
320-
`[closure@src/main.rs:11:36: 15:10 counter:std::rc::Rc<std::sync::Mutex<i32>>]`
230+
`[closure@src/main.rs:11:36: 14:10 counter:std::rc::Rc<std::sync::Mutex<i32>>]`
321231
= note: required by `std::thread::spawn`
322232
```
323233

324-
Wow, that error message is very wordy! Here are some important parts to focus
325-
on: the first inline error says `` `std::rc::Rc<std::sync::Mutex<i32>>` cannot
326-
be sent between threads safely ``. The reason for this is in the next important
327-
part to focus on, the error message. The distilled error message says `` the
328-
trait bound `Send` is not satisfied ``. We’ll talk about `Send` in the next
329-
section: it’s one of the traits that ensures the types we use with threads are
330-
meant for use in concurrent situations.
234+
Wow, that error message is very wordy! Here’s the important part to focus
235+
on: `` `Rc<Mutex<i32>>` cannot be sent between threads safely ``. The compiler
236+
is also telling us the reason why: ``the trait `Send` is not implemented for
237+
`Rc<Mutex<i32>>` ``. We’ll talk about `Send` in the next section: it’s one of
238+
the traits that ensures the types we use with threads are meant for use in
239+
concurrent situations.
331240

332241
Unfortunately, `Rc<T>` is not safe to share across threads. When `Rc<T>`
333242
manages the reference count, it adds to the count for each call to `clone` and

0 commit comments

Comments
 (0)