From d88497ddf2f4a26f6328561a070ab4dd4a053bd1 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 9 Jul 2012 19:04:17 -0700 Subject: [PATCH] tutorial: Overhaul task section --- doc/tutorial.md | 113 +++++++++++++++++++++++++++--------------------- 1 file changed, 63 insertions(+), 50 deletions(-) diff --git a/doc/tutorial.md b/doc/tutorial.md index b30192d678878..8f44bdb34817c 100644 --- a/doc/tutorial.md +++ b/doc/tutorial.md @@ -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 @@ -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)); } ~~~~ @@ -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::(); -let chan = comm::chan::(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::(); -~~~~ 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::(); -let chan = comm::chan::(port); +# import comm::{port, chan, methods}; +# let port = port::(); +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::(); -# let chan = comm::chan::(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); } ~~~~ @@ -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::(); -# let chan = comm::chan::(port); -# comm::send(chan, 0); +# let port = port::(); +# let chan = chan::(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 @@ -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, - to_parent: comm::chan) { +# import comm::{port, chan, methods}; +fn stringifier(from_parent: port, + to_parent: chan) { 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; } } } @@ -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, # to_parent: comm::chan) { # 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 @@ -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.