diff --git a/src/doc/trpl/concurrency.md b/src/doc/trpl/concurrency.md index e00fe75013e..7028bade6de 100644 --- a/src/doc/trpl/concurrency.md +++ b/src/doc/trpl/concurrency.md @@ -26,8 +26,8 @@ to help us make sense of code that can possibly be concurrent. ### `Send` The first trait we're going to talk about is -[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it indicates -to the compiler that something of this type is able to have ownership transferred +[`Send`](../std/marker/trait.Send.html). When a type `T` implements `Send`, it +indicates that something of this type is able to have ownership transferred safely between threads. This is important to enforce certain restrictions. For example, if we have a @@ -42,13 +42,19 @@ us enforce that it can't leave the current thread. ### `Sync` The second of these traits is called [`Sync`](../std/marker/trait.Sync.html). -When a type `T` implements `Sync`, it indicates to the compiler that something +When a type `T` implements `Sync`, it indicates that something of this type has no possibility of introducing memory unsafety when used from -multiple threads concurrently. +multiple threads concurrently through shared references. This implies that +types which don't have [interior mutability](mutability.html) are inherently +`Sync`, which includes simple primitive types (like `u8`) and aggregate types +containing them. -For example, sharing immutable data with an atomic reference count is -threadsafe. Rust provides a type like this, `Arc`, and it implements `Sync`, -so it is safe to share between threads. +For sharing references across threads, Rust provides a wrapper type called +`Arc`. `Arc` implements `Send` and `Sync` if and only if `T` implements +both `Send` and `Sync`. For example, an object of type `Arc>` cannot +be transferred across threads because +[`RefCell`](choosing-your-guarantees.html#refcell%3Ct%3E) does not implement +`Sync`, consequently `Arc>` would not implement `Send`. These two traits allow you to use the type system to make strong guarantees about the properties of your code under concurrency. Before we demonstrate @@ -70,7 +76,7 @@ fn main() { } ``` -The `thread::spawn()` method accepts a closure, which is executed in a +The `thread::spawn()` method accepts a [closure](closures.html), which is executed in a new thread. It returns a handle to the thread, that can be used to wait for the child thread to finish and extract its result: @@ -215,29 +221,18 @@ fn main() { } ``` +Note that the value of `i` is bound (copied) to the closure and not shared +among the threads. -If we'd tried to use `Mutex` without wrapping it in an `Arc` we would have -seen another error like: - -```text -error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` [E0277] - thread::spawn(move || { - ^~~~~~~~~~~~~ -note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec>` cannot be sent between threads safely - thread::spawn(move || { - ^~~~~~~~~~~~~ -``` - -You see, [`Mutex`](../std/sync/struct.Mutex.html) has a -[`lock`](../std/sync/struct.Mutex.html#method.lock) -method which has this signature: +Also note that [`lock`](../std/sync/struct.Mutex.html#method.lock) method of +[`Mutex`](../std/sync/struct.Mutex.html) has this signature: ```ignore fn lock(&self) -> LockResult> ``` -and because `Send` is not implemented for `MutexGuard`, we couldn't have -transferred the guard across thread boundaries on it's own. +and because `Send` is not implemented for `MutexGuard`, the guard cannot +cross thread boundaries, ensuring thread-locality of lock acquire and release. Let's examine the body of the thread more closely: @@ -317,22 +312,24 @@ use std::sync::mpsc; fn main() { let (tx, rx) = mpsc::channel(); - for _ in 0..10 { + for i in 0..10 { let tx = tx.clone(); thread::spawn(move || { - let answer = 42; + let answer = i * i; tx.send(answer); }); } - rx.recv().ok().expect("Could not receive answer"); + for _ in 0..10 { + println!("{}", rx.recv().unwrap()); + } } ``` -A `u32` is `Send` because we can make a copy. So we create a thread, ask it to calculate -the answer, and then it `send()`s us the answer over the channel. +Here we create 10 threads, asking each to calculate the square of a number (`i` +at the time of `spawn()`), and then `send()` back the answer over the channel. ## Panics