rollup merge of #24385: aturon/unstable-scoped
Conflicts: src/libstd/thread/mod.rs src/test/bench/shootout-mandelbrot.rs src/test/bench/shootout-reverse-complement.rs src/test/run-pass/capturing-logging.rs src/test/run-pass/issue-9396.rs src/test/run-pass/tcp-accept-stress.rs src/test/run-pass/tcp-connect-timeouts.rs src/test/run-pass/tempfile.rs
This commit is contained in:
commit
b9d9a376ea
51 changed files with 544 additions and 138 deletions
|
|
@ -389,6 +389,7 @@ safe concurrent programs.
|
|||
Here's an example of a concurrent Rust program:
|
||||
|
||||
```{rust}
|
||||
# #![feature(scoped)]
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
|
|
@ -421,6 +422,7 @@ problem.
|
|||
Let's see an example. This Rust code will not compile:
|
||||
|
||||
```{rust,ignore}
|
||||
# #![feature(scoped)]
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
|
|
@ -467,6 +469,7 @@ that our mutation doesn't cause a data race.
|
|||
Here's what using a Mutex looks like:
|
||||
|
||||
```{rust}
|
||||
# #![feature(scoped)]
|
||||
use std::thread;
|
||||
use std::sync::Mutex;
|
||||
|
||||
|
|
@ -527,6 +530,7 @@ As an example, Rust's ownership system is _entirely_ at compile time. The
|
|||
safety check that makes this an error about moved values:
|
||||
|
||||
```{rust,ignore}
|
||||
# #![feature(scoped)]
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -56,67 +56,34 @@ place!
|
|||
|
||||
## Threads
|
||||
|
||||
Rust's standard library provides a library for 'threads', which allow you to
|
||||
Rust's standard library provides a library for threads, which allow you to
|
||||
run Rust code in parallel. Here's a basic example of using `std::thread`:
|
||||
|
||||
```
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
thread::scoped(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
The `thread::scoped()` method accepts a closure, which is executed in a new
|
||||
thread. It's called `scoped` because this thread returns a join guard:
|
||||
|
||||
```
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let guard = thread::scoped(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
|
||||
// guard goes out of scope here
|
||||
}
|
||||
```
|
||||
|
||||
When `guard` goes out of scope, it will block execution until the thread is
|
||||
finished. If we didn't want this behaviour, we could use `thread::spawn()`:
|
||||
|
||||
```
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
thread::spawn(|| {
|
||||
println!("Hello from a thread!");
|
||||
});
|
||||
|
||||
thread::sleep_ms(50);
|
||||
}
|
||||
```
|
||||
|
||||
We need to `sleep` here because when `main()` ends, it kills all of the
|
||||
running threads.
|
||||
The `thread::spawn()` method accepts a closure, 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:
|
||||
|
||||
[`scoped`](std/thread/struct.Builder.html#method.scoped) has an interesting
|
||||
type signature:
|
||||
|
||||
```text
|
||||
fn scoped<'a, T, F>(self, f: F) -> JoinGuard<'a, T>
|
||||
where T: Send + 'a,
|
||||
F: FnOnce() -> T,
|
||||
F: Send + 'a
|
||||
```
|
||||
use std::thread;
|
||||
|
||||
Specifically, `F`, the closure that we pass to execute in the new thread. It
|
||||
has two restrictions: It must be a `FnOnce` from `()` to `T`. Using `FnOnce`
|
||||
allows the closure to take ownership of any data it mentions from the parent
|
||||
thread. The other restriction is that `F` must be `Send`. We aren't allowed to
|
||||
transfer this ownership unless the type thinks that's okay.
|
||||
fn main() {
|
||||
let handle = thread::spawn(|| {
|
||||
"Hello from a thread!"
|
||||
});
|
||||
|
||||
println!("{}", handle.join().unwrap());
|
||||
}
|
||||
```
|
||||
|
||||
Many languages have the ability to execute threads, but it's wildly unsafe.
|
||||
There are entire books about how to prevent errors that occur from shared
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue