Skip to content

Commit

Permalink
tutorial: Overhaul task section
Browse files Browse the repository at this point in the history
  • Loading branch information
brson committed Jul 10, 2012
1 parent 172bf3a commit d88497d
Showing 1 changed file with 63 additions and 50 deletions.
113 changes: 63 additions & 50 deletions doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -2830,8 +2830,8 @@ supposed to point at, this is safe.
Rust supports a system of lightweight tasks, similar to what is found
in Erlang or other actor systems. Rust tasks communicate via messages
and do not share data. However, it is possible to send data without
copying it by making use of [unique boxes](#unique-boxes), which allow
the sending task to release ownership of a value, so that the
copying it by making use of [the exchange heap](#unique-boxes), which
allow the sending task to release ownership of a value, so that the
receiving task can keep on using it.

> ***Note:*** As Rust evolves, we expect the task API to grow and
Expand All @@ -2843,10 +2843,13 @@ Spawning a task is done using the various spawn functions in the
module `task`. Let's begin with the simplest one, `task::spawn()`:

~~~~
import task::spawn;
import io::println;
let some_value = 22;
do task::spawn {
io::println("This executes in the child task.");
io::println(#fmt("%d", some_value));
do spawn {
println("This executes in the child task.");
println(#fmt("%d", some_value));
}
~~~~

Expand All @@ -2866,44 +2869,54 @@ For example, imagine we wish to perform two expensive computations
in parallel. We might write something like:

~~~~
# fn some_expensive_computation() -> int { 42 }
# fn some_other_expensive_computation() {}
let port = comm::port::<int>();
let chan = comm::chan::<int>(port);
do task::spawn {
import task::spawn;
import comm::{port, chan, methods};
let port = port();
let chan = port.chan();
do spawn {
let result = some_expensive_computation();
comm::send(chan, result);
chan.send(result);
}
some_other_expensive_computation();
let result = comm::recv(port);
let result = port.recv();
# fn some_expensive_computation() -> int { 42 }
# fn some_other_expensive_computation() {}
~~~~

Let's walk through this code line-by-line. The first line creates a
port for receiving integers:

~~~~ {.ignore}
# import comm::port;
let port = port();
~~~~
let port = comm::port::<int>();

~~~~
This port is where we will receive the message from the child task
once it is complete. The second line creates a channel for sending
integers to the port `port`:

~~~~
# let port = comm::port::<int>();
let chan = comm::chan::<int>(port);
# import comm::{port, chan, methods};
# let port = port::<int>();
let chan = port.chan();
~~~~

The channel will be used by the child to send a message to the port.
The next statement actually spawns the child:

~~~~
# import task::{spawn};
# import comm::{port, chan, methods};
# fn some_expensive_computation() -> int { 42 }
# let port = comm::port::<int>();
# let chan = comm::chan::<int>(port);
do task::spawn {
# let port = port();
# let chan = port.chan();
do spawn {
let result = some_expensive_computation();
comm::send(chan, result);
chan.send(result);
}
~~~~

Expand All @@ -2913,12 +2926,13 @@ some other expensive computation and then waiting for the child's result
to arrive on the port:

~~~~
# import comm::{port, chan, methods};
# fn some_other_expensive_computation() {}
# let port = comm::port::<int>();
# let chan = comm::chan::<int>(port);
# comm::send(chan, 0);
# let port = port::<int>();
# let chan = chan::<int>(port);
# chan.send(0);
some_other_expensive_computation();
let result = comm::recv(port);
let result = port.recv();
~~~~

## Creating a task with a bi-directional communication path
Expand All @@ -2934,12 +2948,13 @@ the string in response. The child terminates when `0` is received.
Here is the function which implements the child task:

~~~~
fn stringifier(from_parent: comm::port<uint>,
to_parent: comm::chan<str>) {
# import comm::{port, chan, methods};
fn stringifier(from_parent: port<uint>,
to_parent: chan<str>) {
let mut value: uint;
loop {
value = comm::recv(from_parent);
comm::send(to_parent, uint::to_str(value, 10u));
value = from_parent.recv();
to_parent.send(uint::to_str(value, 10u));
if value == 0u { break; }
}
}
Expand All @@ -2956,25 +2971,32 @@ simply the strified version of the received value,
Here is the code for the parent task:

~~~~
# import task::{spawn_listener};
# import comm::{chan, port, methods};
# fn stringifier(from_parent: comm::port<uint>,
# to_parent: comm::chan<str>) {
# comm::send(to_parent, "22");
# comm::send(to_parent, "23");
# comm::send(to_parent, "0");
# }
fn main() {
let from_child = comm::port();
let to_parent = comm::chan(from_child);
let to_child = do task::spawn_listener |from_parent| {
stringifier(from_parent, to_parent);
};
comm::send(to_child, 22u);
assert comm::recv(from_child) == "22";
comm::send(to_child, 23u);
assert comm::recv(from_child) == "23";
comm::send(to_child, 0u);
assert comm::recv(from_child) == "0";
}
# fn main() {
let from_child = port();
let to_parent = from_child.chan();
let to_child = do spawn_listener |from_parent| {
stringifier(from_parent, to_parent);
};
to_child.send(22u);
assert from_child.recv() == "22";
to_child.send(23u);
assert from_child.recv() == "23";
to_child.send(0u);
assert from_child.recv() == "0";
# }
~~~~

The parent first sets up a port to receive data from and a channel
Expand All @@ -2986,15 +3008,6 @@ the associated channel. Finally, the closure passed to
`to_parent` channel in its environment, so both parent and child
can send and receive data to and from the other.

## The supervisor relationship

By default, failures in Rust propagate upward through the task tree.
We say that each task is supervised by its parent, meaning that if the
task fails, that failure is propagated to the parent task, which will
fail sometime later. This propagation can be disabled by using the
function `task::unsupervise()`, which disables error propagation from
the current task to its parent.

# Testing

The Rust language has a facility for testing built into the language.
Expand Down

0 comments on commit d88497d

Please sign in to comment.