100 exercises to learn Rust
This commit is contained in:
73
book/src/07_threads/04_scoped_threads.md
Normal file
73
book/src/07_threads/04_scoped_threads.md
Normal file
@@ -0,0 +1,73 @@
|
||||
# Scoped threads
|
||||
|
||||
All the lifetime issues we discussed so far have a common source:
|
||||
the spawned thread can outlive its parent.
|
||||
We can sidestep this issue by using **scoped threads**.
|
||||
|
||||
```rust
|
||||
let v = vec![1, 2, 3];
|
||||
let midpoint = v.len() / 2;
|
||||
|
||||
std::thread::scope(|scope| {
|
||||
scope.spawn(|| {
|
||||
let first = &v[..midpoint];
|
||||
println!("Here's the first half of v: {first:?}");
|
||||
});
|
||||
scope.spawn(|| {
|
||||
let second = &v[midpoint..];
|
||||
println!("Here's the second half of v: {second:?}");
|
||||
});
|
||||
});
|
||||
|
||||
println!("Here's v: {v:?}");
|
||||
```
|
||||
|
||||
Let's unpack what's happening.
|
||||
|
||||
## `scope`
|
||||
|
||||
The `std::thread::scope` function creates a new **scope**.
|
||||
`std::thread::scope` takes as input a closure, with a single argument: a `Scope` instance.
|
||||
|
||||
## Scoped spawns
|
||||
|
||||
`Scope` exposes a `spawn` method.
|
||||
Unlike `std::thread::spawn`, all threads spawned using a `Scope` will be
|
||||
**automatically joined** when the scope ends.
|
||||
|
||||
If we were to "translate" the previous example to `std::thread::spawn`,
|
||||
it'd look like this:
|
||||
|
||||
```rust
|
||||
let v = vec![1, 2, 3];
|
||||
let midpoint = v.len() / 2;
|
||||
|
||||
let handle1 = std::thread::spawn(|| {
|
||||
let first = &v[..midpoint];
|
||||
println!("Here's the first half of v: {first:?}");
|
||||
});
|
||||
let handle2 = std::thread::spawn(|| {
|
||||
let second = &v[midpoint..];
|
||||
println!("Here's the second half of v: {second:?}");
|
||||
});
|
||||
|
||||
handle1.join().unwrap();
|
||||
handle2.join().unwrap();
|
||||
|
||||
println!("Here's v: {v:?}");
|
||||
```
|
||||
|
||||
## Borrowing from the environment
|
||||
|
||||
The translated example wouldn't compile, though: the compiler would complain
|
||||
that `&v` can't be used from our spawned threads since its lifetime isn't
|
||||
`'static`.
|
||||
|
||||
That's not an issue with `std::thread::scope`—you can **safely borrow from the environment**.
|
||||
|
||||
In our example, `v` is created before the spawning points.
|
||||
It will only be dropped _after_ `scope` returns. At the same time,
|
||||
all threads spawned inside `scope` are guaranteed `v` is dropped,
|
||||
therefore there is no risk of having dangling references.
|
||||
|
||||
The compiler won't complain!
|
||||
Reference in New Issue
Block a user