Skip to content

Commit 06ba908

Browse files
committed
update original
1 parent f5431e1 commit 06ba908

7 files changed

Lines changed: 236 additions & 238 deletions

rustbook-en/nostarch/chapter16.md

Lines changed: 157 additions & 158 deletions
Large diffs are not rendered by default.
8.37 KB
Binary file not shown.

rustbook-en/src/ch16-00-concurrency.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@ than making you spend lots of time trying to reproduce the exact circumstances
1818
under which a runtime concurrency bug occurs, incorrect code will refuse to
1919
compile and present an error explaining the problem. As a result, you can fix
2020
your code while you’re working on it rather than potentially after it has been
21-
shipped to production. We’ve nicknamed this aspect of Rust _fearless_
22-
_concurrency_. Fearless concurrency allows you to write code that is free of
21+
shipped to production. We’ve nicknamed this aspect of Rust _fearless
22+
concurrency_. Fearless concurrency allows you to write code that is free of
2323
subtle bugs and is easy to refactor without introducing new bugs.
2424

2525
> Note: For simplicity’s sake, we’ll refer to many of the problems as
2626
> _concurrent_ rather than being more precise by saying _concurrent and/or
27-
> parallel_. For this chapter, please mentally substitute _concurrent
28-
> and/or parallel_ whenever we use _concurrent_. In the next chapter, where the
27+
> parallel_. For this chapter, please mentally substitute _concurrent and/or
28+
> parallel_ whenever we use _concurrent_. In the next chapter, where the
2929
> distinction matters more, we’ll be more specific.
3030
3131
Many languages are dogmatic about the solutions they offer for handling
3232
concurrent problems. For example, Erlang has elegant functionality for
3333
message-passing concurrency but has only obscure ways to share state between
3434
threads. Supporting only a subset of possible solutions is a reasonable
35-
strategy for higher-level languages, because a higher-level language promises
35+
strategy for higher-level languages because a higher-level language promises
3636
benefits from giving up some control to gain abstractions. However, lower-level
3737
languages are expected to provide the solution with the best performance in any
3838
given situation and have fewer abstractions over the hardware. Therefore, Rust

rustbook-en/src/ch16-01-threads.md

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ to problems, such as:
1717
inconsistent order
1818
- Deadlocks, in which two threads are waiting for each other, preventing both
1919
threads from continuing
20-
- Bugs that happen only in certain situations and are hard to reproduce and fix
20+
- Bugs that only happen in certain situations and are hard to reproduce and fix
2121
reliably
2222

2323
Rust attempts to mitigate the negative effects of using threads, but
@@ -26,19 +26,19 @@ a code structure that is different from that in programs running in a single
2626
thread.
2727

2828
Programming languages implement threads in a few different ways, and many
29-
operating systems provide an API the language can call for creating new threads.
30-
The Rust standard library uses a _1:1_ model of thread implementation, whereby a
31-
program uses one operating system thread per one language thread. There are
32-
crates that implement other models of threading that make different tradeoffs to
33-
the 1:1 model. (Rust’s async system, which we will see in the next chapter,
34-
provides another approach to concurrency as well.)
29+
operating systems provide an API the programming language can call for creating
30+
new threads. The Rust standard library uses a _1:1_ model of thread
31+
implementation, whereby a program uses one operating system thread per one
32+
language thread. There are crates that implement other models of threading that
33+
make different trade-offs to the 1:1 model. (Rust’s async system, which we will
34+
see in the next chapter, provides another approach to concurrency as well.)
3535

3636
### Creating a New Thread with `spawn`
3737

3838
To create a new thread, we call the `thread::spawn` function and pass it a
3939
closure (we talked about closures in Chapter 13) containing the code we want to
4040
run in the new thread. The example in Listing 16-1 prints some text from a main
41-
thread and other text from a new thread:
41+
thread and other text from a new thread.
4242

4343
<Listing number="16-1" file-name="src/main.rs" caption="Creating a new thread to print one thing while the main thread prints something else">
4444

@@ -88,13 +88,13 @@ the time due to the main thread ending, but because there is no guarantee on
8888
the order in which threads run, we also can’t guarantee that the spawned thread
8989
will get to run at all!
9090

91-
We can fix the problem of the spawned thread not running or ending prematurely
92-
by saving the return value of `thread::spawn` in a variable. The return type of
93-
`thread::spawn` is `JoinHandle<T>`. A `JoinHandle<T>` is an owned value that,
94-
when we call the `join` method on it, will wait for its thread to finish.
95-
Listing 16-2 shows how to use the `JoinHandle<T>` of the thread we created in
96-
Listing 16-1 and how to call `join` to make sure the spawned thread finishes
97-
before `main` exits.
91+
We can fix the problem of the spawned thread not running or of it ending
92+
prematurely by saving the return value of `thread::spawn` in a variable. The
93+
return type of `thread::spawn` is `JoinHandle<T>`. A `JoinHandle<T>` is an
94+
owned value that, when we call the `join` method on it, will wait for its
95+
thread to finish. Listing 16-2 shows how to use the `JoinHandle<T>` of the
96+
thread we created in Listing 16-1 and how to call `join` to make sure the
97+
spawned thread finishes before `main` exits.
9898

9999
<Listing number="16-2" file-name="src/main.rs" caption="Saving a `JoinHandle<T>` from `thread::spawn` to guarantee the thread is run to completion">
100100

@@ -172,11 +172,11 @@ threads run at the same time.
172172

173173
### Using `move` Closures with Threads
174174

175-
We'll often use the `move` keyword with closures passed to `thread::spawn`
175+
Well often use the `move` keyword with closures passed to `thread::spawn`
176176
because the closure will then take ownership of the values it uses from the
177177
environment, thus transferring ownership of those values from one thread to
178-
another. In [“Capturing the Environment With Closures][capture]<!-- ignore -->
179-
in Chapter 13, we discussed `move` in the context of closures. Now, we’ll
178+
another. In [“Capturing References or Moving Ownership][capture]<!-- ignore
179+
--> in Chapter 13, we discussed `move` in the context of closures. Now we’ll
180180
concentrate more on the interaction between `move` and `thread::spawn`.
181181

182182
Notice in Listing 16-1 that the closure we pass to `thread::spawn` takes no
@@ -209,7 +209,7 @@ tell how long the spawned thread will run, so it doesn’t know whether the
209209
reference to `v` will always be valid.
210210

211211
Listing 16-4 provides a scenario that’s more likely to have a reference to `v`
212-
that won’t be valid:
212+
that won’t be valid.
213213

214214
<Listing number="16-4" file-name="src/main.rs" caption="A thread with a closure that attempts to capture a reference to `v` from a main thread that drops `v`">
215215

@@ -277,4 +277,4 @@ ownership rules.
277277
Now that we’ve covered what threads are and the methods supplied by the thread
278278
API, let’s look at some situations in which we can use threads.
279279

280-
[capture]: ch13-01-closures.html#capturing-the-environment-with-closures
280+
[capture]: ch13-01-closures.html#capturing-references-or-moving-ownership

rustbook-en/src/ch16-02-message-passing.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ passing_, where threads or actors communicate by sending each other messages
55
containing data. Here’s the idea in a slogan from [the Go language documentation](https://golang.org/doc/effective_go.html#concurrency):
66
“Do not communicate by sharing memory; instead, share memory by communicating.”
77

8-
To accomplish message-sending concurrency, Rust's standard library provides an
8+
To accomplish message-sending concurrency, Rusts standard library provides an
99
implementation of channels. A _channel_ is a general programming concept by
1010
which data is sent from one thread to another.
1111

@@ -51,13 +51,13 @@ working.
5151

5252
The `mpsc::channel` function returns a tuple, the first element of which is the
5353
sending end—the transmitter—and the second element of which is the receiving
54-
end—the receiver. The abbreviations `tx` and `rx` are traditionally used in many
55-
fields for _transmitter_ and _receiver_, respectively, so we name our variables
56-
as such to indicate each end. We’re using a `let` statement with a pattern that
57-
destructures the tuples; we’ll discuss the use of patterns in `let` statements
58-
and destructuring in Chapter 19. For now, know that using a `let` statement this
59-
way is a convenient approach to extract the pieces of the tuple returned by
60-
`mpsc::channel`.
54+
end—the receiver. The abbreviations `tx` and `rx` are traditionally used in
55+
many fields for _transmitter_ and _receiver_, respectively, so we name our
56+
variables as such to indicate each end. We’re using a `let` statement with a
57+
pattern that destructures the tuples; we’ll discuss the use of patterns in
58+
`let` statements and destructuring in Chapter 19. For now, know that using a
59+
`let` statement in this way is a convenient approach to extract the pieces of
60+
the tuple returned by `mpsc::channel`.
6161

6262
Let’s move the transmitting end into a spawned thread and have it send one
6363
string so the spawned thread is communicating with the main thread, as shown in
@@ -156,18 +156,19 @@ us an error if we try to compile the code in Listing 16-9:
156156
{{#include ../listings/ch16-fearless-concurrency/listing-16-09/output.txt}}
157157
```
158158

159-
Our concurrency mistake has caused a compile time error. The `send` function
160-
takes ownership of its parameter, and when the value is moved, the receiver
159+
Our concurrency mistake has caused a compile-time error. The `send` function
160+
takes ownership of its parameter, and when the value is moved the receiver
161161
takes ownership of it. This stops us from accidentally using the value again
162162
after sending it; the ownership system checks that everything is okay.
163163

164164
### Sending Multiple Values and Seeing the Receiver Waiting
165165

166166
The code in Listing 16-8 compiled and ran, but it didn’t clearly show us that
167-
two separate threads were talking to each other over the channel. In Listing
168-
16-10 we’ve made some modifications that will prove the code in Listing 16-8 is
169-
running concurrently: the spawned thread will now send multiple messages and
170-
pause for a second between each message.
167+
two separate threads were talking to each other over the channel.
168+
169+
In Listing 16-10 we’ve made some modifications that will prove the code in
170+
Listing 16-8 is running concurrently: the spawned thread will now send multiple
171+
messages and pause for a second between each message.
171172

172173
<Listing number="16-10" file-name="src/main.rs" caption="Sending multiple messages and pausing between each one">
173174

rustbook-en/src/ch16-03-shared-state.md

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
## Shared-State Concurrency
22

3-
Message passing is a fine way to handle concurrency, but it’s not the only
4-
way. Another method would be for multiple threads to access the same shared
5-
data. Consider this part of the slogan from the Go language documentation
6-
again: “Do not communicate by sharing memory.”
3+
Message passing is a fine way to handle concurrency, but it’s not the only way.
4+
Another method would be for multiple threads to access the same shared data.
5+
Consider this part of the slogan from the Go language documentation again: “Do
6+
not communicate by sharing memory.”
77

88
What would communicating by sharing memory look like? In addition, why would
99
message-passing enthusiasts caution not to use memory sharing?
1010

11-
In a way, channels in any programming language are similar to single ownership,
11+
In a way, channels in any programming language are similar to single ownership
1212
because once you transfer a value down a channel, you should no longer use that
1313
value. Shared-memory concurrency is like multiple ownership: multiple threads
1414
can access the same memory location at the same time. As you saw in Chapter 15,
@@ -23,7 +23,7 @@ for shared memory.
2323
_Mutex_ is an abbreviation for _mutual exclusion_, as in a mutex allows only
2424
one thread to access some data at any given time. To access the data in a
2525
mutex, a thread must first signal that it wants access by asking to acquire the
26-
mutex’s _lock_. The lock is a data structure that is part of the mutex that
26+
mutex’s lock. The _lock_ is a data structure that is part of the mutex that
2727
keeps track of who currently has exclusive access to the data. Therefore, the
2828
mutex is described as _guarding_ the data it holds via the locking system.
2929

@@ -76,18 +76,16 @@ that we acquire a lock before using the value in `m`. The type of `m` is
7676
value. We can’t forget; the type system won’t let us access the inner `i32`
7777
otherwise.
7878

79-
As you might suspect, `Mutex<T>` is a smart pointer. More accurately, the call
80-
to `lock` _returns_ a smart pointer called `MutexGuard`, wrapped in a
81-
`LockResult` that we handled with the call to `unwrap`. The `MutexGuard` smart
82-
pointer implements `Deref` to point at our inner data; the smart pointer also
83-
has a `Drop` implementation that releases the lock automatically when a
84-
`MutexGuard` goes out of scope, which happens at the end of the inner scope. As
85-
a result, we don’t risk forgetting to release the lock and blocking the mutex
86-
from being used by other threads, because the lock release happens
87-
automatically.
79+
The call to `lock` returns a type called `MutexGuard`, wrapped in a
80+
`LockResult` that we handled with the call to `unwrap`. The `MutexGuard` type
81+
implements `Deref` to point at our inner data; the type also has a `Drop`
82+
implementation that releases the lock automatically when a `MutexGuard` goes
83+
out of scope, which happens at the end of the inner scope. As a result, we
84+
don’t risk forgetting to release the lock and blocking the mutex from being
85+
used by other threads because the lock release happens automatically.
8886

8987
After dropping the lock, we can print the mutex value and see that we were able
90-
to change the inner `i32` to 6.
88+
to change the inner `i32` to `6`.
9189

9290
#### Sharing a `Mutex<T>` Between Multiple Threads
9391

@@ -125,8 +123,8 @@ We hinted that this example wouldn’t compile. Now let’s find out why!
125123
```
126124

127125
The error message states that the `counter` value was moved in the previous
128-
iteration of the loop. Rust is telling us that we can’t move the ownership
129-
of lock `counter` into multiple threads. Let’s fix the compiler error with the
126+
iteration of the loop. Rust is telling us that we can’t move the ownership of
127+
lock `counter` into multiple threads. Let’s fix the compiler error with the
130128
multiple-ownership method we discussed in Chapter 15.
131129

132130
#### Multiple Ownership with Multiple Threads
@@ -164,7 +162,7 @@ subtracts from the count when each clone is dropped. But it doesn’t use any
164162
concurrency primitives to make sure that changes to the count can’t be
165163
interrupted by another thread. This could lead to wrong counts—subtle bugs that
166164
could in turn lead to memory leaks or a value being dropped before we’re done
167-
with it. What we need is a type that is exactly like `Rc<T>` but one that makes
165+
with it. What we need is a type that is exactly like `Rc<T>`, but that makes
168166
changes to the reference count in a thread-safe way.
169167

170168
#### Atomic Reference Counting with `Arc<T>`

rustbook-en/src/ch16-04-extensible-concurrency-sync-and-send.md

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,29 @@
66

77
Interestingly, almost every concurrency feature we’ve talked about so far in
88
this chapter has been part of the standard library, not the language. Your
9-
options for handling concurrency are not limited to the language or the standard
10-
library; you can write your own concurrency features or use those written by
11-
others.
9+
options for handling concurrency are not limited to the language or the
10+
standard library; you can write your own concurrency features or use those
11+
written by others.
1212

1313
However, among the key concurrency concepts that are embedded in the language
14-
rather than the standard library are the `std::marker` traits `Send` and
15-
`Sync`.
14+
rather than the standard library are the `std::marker` traits `Send` and `Sync`.
1615

1716
### Allowing Transference of Ownership Between Threads with `Send`
1817

1918
The `Send` marker trait indicates that ownership of values of the type
2019
implementing `Send` can be transferred between threads. Almost every Rust type
21-
is `Send`, but there are some exceptions, including `Rc<T>`: this cannot
22-
implement `Send` because if you cloned an `Rc<T>` value and tried to transfer
23-
ownership of the clone to another thread, both threads might update the
24-
reference count at the same time. For this reason, `Rc<T>` is implemented for
25-
use in single-threaded situations where you don’t want to pay the thread-safe
26-
performance penalty.
20+
implements `Send`, but there are some exceptions, including `Rc<T>`: this
21+
cannot implement `Send` because if you cloned an `Rc<T>` value and tried to
22+
transfer ownership of the clone to another thread, both threads might update
23+
the reference count at the same time. For this reason, `Rc<T>` is implemented
24+
for use in single-threaded situations where you don’t want to pay the
25+
thread-safe performance penalty.
2726

2827
Therefore, Rust’s type system and trait bounds ensure that you can never
2928
accidentally send an `Rc<T>` value across threads unsafely. When we tried to do
30-
this in Listing 16-14, we got the error `the trait Send is not implemented for
31-
Rc<Mutex<i32>>`. When we switched to `Arc<T>`, which does implement `Send`, the
32-
code compiled.
29+
this in Listing 16-14, we got the error `` the trait `Send` is not implemented
30+
for `Rc<Mutex<i32>>` ``. When we switched to `Arc<T>`, which does implement
31+
`Send`, the code compiled.
3332

3433
Any type composed entirely of `Send` types is automatically marked as `Send` as
3534
well. Almost all primitive types are `Send`, aside from raw pointers, which
@@ -39,18 +38,19 @@ we’ll discuss in Chapter 20.
3938

4039
The `Sync` marker trait indicates that it is safe for the type implementing
4140
`Sync` to be referenced from multiple threads. In other words, any type `T`
42-
implements `Sync` if `&T` (an immutable reference to `T`) implements `Send`,
41+
implements `Sync` if `&T` (an immutable reference to `T`) implements `Send`,
4342
meaning the reference can be sent safely to another thread. Similar to `Send`,
4443
primitive types all implement `Sync`, and types composed entirely of types that
4544
implement `Sync` also implement `Sync`.
4645

4746
The smart pointer `Rc<T>` also doesn’t implement `Sync` for the same reasons
4847
that it doesn’t implement `Send`. The `RefCell<T>` type (which we talked about
49-
in Chapter 15) and the family of related `Cell<T>` types don’t implement `Sync`.
50-
The implementation of borrow checking that `RefCell<T>` does at runtime is not
51-
thread-safe. The smart pointer `Mutex<T>` implements `Sync` and can be used to
52-
share access with multiple threads as you saw in [“Sharing a `Mutex<T>` Between
53-
Multiple Threads”][sharing-a-mutext-between-multiple-threads]<!-- ignore -->.
48+
in Chapter 15) and the family of related `Cell<T>` types don’t implement
49+
`Sync`. The implementation of borrow checking that `RefCell<T>` does at runtime
50+
is not thread-safe. The smart pointer `Mutex<T>` implements `Sync` and can be
51+
used to share access with multiple threads, as you saw in [“Sharing a
52+
`Mutex<T>` Between Multiple
53+
Threads”][sharing-a-mutext-between-multiple-threads]<!-- ignore -->.
5454

5555
### Implementing `Send` and `Sync` Manually Is Unsafe
5656

@@ -71,8 +71,8 @@ uphold them.
7171

7272
This isn’t the last you’ll see of concurrency in this book: the next chapter
7373
focuses on async programming, and the project in Chapter 21 will use the
74-
concepts in this chapter in a more realistic situation than the smaller examples
75-
discussed here.
74+
concepts in this chapter in a more realistic situation than the smaller
75+
examples discussed here.
7676

7777
As mentioned earlier, because very little of how Rust handles concurrency is
7878
part of the language, many concurrency solutions are implemented as crates.

0 commit comments

Comments
 (0)