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:
Alex Crichton 2015-04-14 10:59:55 -07:00
commit b9d9a376ea
51 changed files with 544 additions and 138 deletions

View file

@ -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() {

View file

@ -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