diff --git a/src/ch16-01-threads.md b/src/ch16-01-threads.md index f3cdbff907..cc64664047 100644 --- a/src/ch16-01-threads.md +++ b/src/ch16-01-threads.md @@ -40,14 +40,13 @@ closure (we talked about closures in Chapter 13) containing the code we want to run in the new thread. The example in Listing 16-1 prints some text from a main thread and other text from a new thread: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-01/src/main.rs}} ``` -Listing 16-1: Creating a new thread to print one thing -while the main thread prints something else + Note that when the main thread of a Rust program completes, all spawned threads are shut down, whether or not they have finished running. The output from this @@ -96,14 +95,13 @@ call the `join` method on it, will wait for its thread to finish. Listing 16-2 shows how to use the `JoinHandle` of the thread we created in Listing 16-1 and call `join` to make sure the spawned thread finishes before `main` exits: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-02/src/main.rs}} ``` -Listing 16-2: Saving a `JoinHandle` from `thread::spawn` -to guarantee the thread is run to completion + Calling `join` on the handle blocks the thread currently running until the thread represented by the handle terminates. *Blocking* a thread means that @@ -137,12 +135,14 @@ call to `handle.join()` and does not end until the spawned thread is finished. But let’s see what happens when we instead move `handle.join()` before the `for` loop in `main`, like this: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/no-listing-01-join-too-early/src/main.rs}} ``` + + The main thread will wait for the spawned thread to finish and then run its `for` loop, so the output won’t be interleaved anymore, as shown here: @@ -185,14 +185,13 @@ spawned thread’s closure must capture the values it needs. Listing 16-3 shows an attempt to create a vector in the main thread and use it in the spawned thread. However, this won’t yet work, as you’ll see in a moment. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-03/src/main.rs}} ``` -Listing 16-3: Attempting to use a vector created by the -main thread in another thread + The closure uses `v`, so it will capture `v` and make it part of the closure’s environment. Because `thread::spawn` runs this closure in a new thread, we @@ -211,14 +210,13 @@ to `v` will always be valid. Listing 16-4 provides a scenario that’s more likely to have a reference to `v` that won’t be valid: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-04/src/main.rs}} ``` -Listing 16-4: A thread with a closure that attempts to -capture a reference to `v` from a main thread that drops `v` + If Rust allowed us to run this code, there’s a possibility the spawned thread would be immediately put in the background without running at all. The spawned @@ -246,14 +244,14 @@ ownership of the values it’s using rather than allowing Rust to infer that it should borrow the values. The modification to Listing 16-3 shown in Listing 16-5 will compile and run as we intend: -Filename: src/main.rs ++ ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-05/src/main.rs}} ``` -Listing 16-5: Using the `move` keyword to force a closure -to take ownership of the values it uses + We might be tempted to try the same thing to fix the code in Listing 16-4 where the main thread called `drop` by using a `move` closure. However, this fix will diff --git a/src/ch16-02-message-passing.md b/src/ch16-02-message-passing.md index 3782fa5dec..f2d396bfaa 100644 --- a/src/ch16-02-message-passing.md +++ b/src/ch16-02-message-passing.md @@ -66,14 +66,13 @@ string so the spawned thread is communicating with the main thread, as shown in Listing 16-7. This is like putting a rubber duck in the river upstream or sending a chat message from one thread to another. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-07/src/main.rs}} ``` -Listing 16-7: Moving `tx` to a spawned thread and sending -“hi” + Again, we’re using `thread::spawn` to create a new thread and then using `move` to move `tx` into the closure so the spawned thread owns `tx`. The spawned @@ -89,14 +88,13 @@ In Listing 16-8, we’ll get the value from the receiver in the main thread. Thi is like retrieving the rubber duck from the water at the end of the river or receiving a chat message. -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-08/src/main.rs}} ``` -Listing 16-8: Receiving the value “hi” in the main thread -and printing it + The receiver has two useful methods: `recv` and `try_recv`. We’re using `recv`, short for *receive*, which will block the main thread’s execution and wait @@ -139,14 +137,13 @@ problems: we’ll try to use a `val` value in the spawned thread *after* we’ve sent it down the channel. Try compiling the code in Listing 16-9 to see why this code isn’t allowed: -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-09/src/main.rs}} ``` -Listing 16-9: Attempting to use `val` after we’ve sent it -down the channel + Here, we try to print `val` after we’ve sent it down the channel via `tx.send`. Allowing this would be a bad idea: once the value has been sent to another @@ -172,14 +169,13 @@ two separate threads were talking to each other over the channel. In Listing running concurrently: the spawned thread will now send multiple messages and pause for a second between each message. -Filename: src/main.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-10/src/main.rs}} ``` -Listing 16-10: Sending multiple messages and pausing -between each + This time, the spawned thread has a vector of strings that we want to send to the main thread. We iterate over them, sending each individually, and pause @@ -215,14 +211,13 @@ single consumer*. Let’s put `mpsc` to use and expand the code in Listing 16-10 to create multiple threads that all send values to the same receiver. We can do so by cloning the transmitter, as shown in Listing 16-11: -Filename: src/main.rs + ```rust,noplayground {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-11/src/main.rs:here}} ``` -Listing 16-11: Sending multiple messages from multiple -producers + This time, before we create the first spawned thread, we call `clone` on the transmitter. This will give us a new transmitter we can pass to the first diff --git a/src/ch16-03-shared-state.md b/src/ch16-03-shared-state.md index a5f806c5bf..d319c6d6c2 100644 --- a/src/ch16-03-shared-state.md +++ b/src/ch16-03-shared-state.md @@ -52,14 +52,13 @@ system and ownership rules, you can’t get locking and unlocking wrong. As an example of how to use a mutex, let’s start by using a mutex in a single-threaded context, as shown in Listing 16-12: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-12/src/main.rs}} ``` -Listing 16-12: Exploring the API of `Mutex` in a -single-threaded context for simplicity + As with many types, we create a `Mutex` using the associated function `new`. To access the data inside the mutex, we use the `lock` method to acquire the @@ -98,14 +97,13 @@ the counter goes from 0 to 10. The next example in Listing 16-13 will have a compiler error, and we’ll use that error to learn more about using `Mutex` and how Rust helps us use it correctly. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-13/src/main.rs}} ``` -Listing 16-13: Ten threads each increment a counter -guarded by a `Mutex` + We create a `counter` variable to hold an `i32` inside a `Mutex`, as we did in Listing 16-12. Next, we create 10 threads by iterating over a range of @@ -138,14 +136,13 @@ In Chapter 15, we gave a value multiple owners by using the smart pointer what happens. We’ll wrap the `Mutex` in `Rc` in Listing 16-14 and clone the `Rc` before moving ownership to the thread. -Filename: src/main.rs + ```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-14/src/main.rs}} ``` -Listing 16-14: Attempting to use `Rc` to allow -multiple threads to own the `Mutex` + Once again, we compile and get... different errors! The compiler is teaching us a lot. @@ -191,14 +188,13 @@ Let’s return to our example: `Arc` and `Rc` have the same API, so we fix our program by changing the `use` line, the call to `new`, and the call to `clone`. The code in Listing 16-15 will finally compile and run: -Filename: src/main.rs + ```rust {{#rustdoc_include ../listings/ch16-fearless-concurrency/listing-16-15/src/main.rs}} ``` -Listing 16-15: Using an `Arc` to wrap the `Mutex` -to be able to share ownership across multiple threads + This code will print the following: