@@ -2830,8 +2830,8 @@ supposed to point at, this is safe.
2830
2830
Rust supports a system of lightweight tasks, similar to what is found
2831
2831
in Erlang or other actor systems. Rust tasks communicate via messages
2832
2832
and do not share data. However, it is possible to send data without
2833
- copying it by making use of [unique boxes ](#unique-boxes), which allow
2834
- the sending task to release ownership of a value, so that the
2833
+ copying it by making use of [the exchange heap ](#unique-boxes), which
2834
+ allow the sending task to release ownership of a value, so that the
2835
2835
receiving task can keep on using it.
2836
2836
2837
2837
> ***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
2843
2843
module `task`. Let's begin with the simplest one, `task::spawn()`:
2844
2844
2845
2845
~~~~
2846
+ import task::spawn;
2847
+ import io::println;
2848
+
2846
2849
let some_value = 22;
2847
- do task:: spawn {
2848
- io:: println("This executes in the child task.");
2849
- io:: println(#fmt("%d", some_value));
2850
+ do spawn {
2851
+ println("This executes in the child task.");
2852
+ println(#fmt("%d", some_value));
2850
2853
}
2851
2854
~~~~
2852
2855
@@ -2866,44 +2869,54 @@ For example, imagine we wish to perform two expensive computations
2866
2869
in parallel. We might write something like:
2867
2870
2868
2871
~~~~
2869
- # fn some_expensive_computation() -> int { 42 }
2870
- # fn some_other_expensive_computation() {}
2871
- let port = comm::port::<int>();
2872
- let chan = comm::chan::<int>(port);
2873
- do task::spawn {
2872
+ import task::spawn;
2873
+ import comm::{port, chan, methods};
2874
+
2875
+ let port = port();
2876
+ let chan = port.chan();
2877
+
2878
+ do spawn {
2874
2879
let result = some_expensive_computation();
2875
- comm:: send(chan, result);
2880
+ chan. send(result);
2876
2881
}
2882
+
2877
2883
some_other_expensive_computation();
2878
- let result = comm::recv(port);
2884
+ let result = port.recv();
2885
+
2886
+ # fn some_expensive_computation() -> int { 42 }
2887
+ # fn some_other_expensive_computation() {}
2879
2888
~~~~
2880
2889
2881
2890
Let's walk through this code line-by-line. The first line creates a
2882
2891
port for receiving integers:
2883
2892
2893
+ ~~~~ {.ignore}
2894
+ # import comm::port;
2895
+ let port = port();
2884
2896
~~~~
2885
- let port = comm::port::<int>();
2886
2897
2887
- ~~~~
2888
2898
This port is where we will receive the message from the child task
2889
2899
once it is complete. The second line creates a channel for sending
2890
2900
integers to the port `port`:
2891
2901
2892
2902
~~~~
2893
- # let port = comm::port::<int>();
2894
- let chan = comm::chan::<int>(port);
2903
+ # import comm::{port, chan, methods};
2904
+ # let port = port::<int>();
2905
+ let chan = port.chan();
2895
2906
~~~~
2896
2907
2897
2908
The channel will be used by the child to send a message to the port.
2898
2909
The next statement actually spawns the child:
2899
2910
2900
2911
~~~~
2912
+ # import task::{spawn};
2913
+ # import comm::{port, chan, methods};
2901
2914
# fn some_expensive_computation() -> int { 42 }
2902
- # let port = comm:: port::<int> ();
2903
- # let chan = comm:: chan::<int>(port );
2904
- do task:: spawn {
2915
+ # let port = port();
2916
+ # let chan = port. chan( );
2917
+ do spawn {
2905
2918
let result = some_expensive_computation();
2906
- comm:: send(chan, result);
2919
+ chan. send(result);
2907
2920
}
2908
2921
~~~~
2909
2922
@@ -2913,12 +2926,13 @@ some other expensive computation and then waiting for the child's result
2913
2926
to arrive on the port:
2914
2927
2915
2928
~~~~
2929
+ # import comm::{port, chan, methods};
2916
2930
# fn some_other_expensive_computation() {}
2917
- # let port = comm:: port::<int>();
2918
- # let chan = comm:: chan::<int>(port);
2919
- # comm:: send(chan, 0);
2931
+ # let port = port::<int>();
2932
+ # let chan = chan::<int>(port);
2933
+ # chan. send(0);
2920
2934
some_other_expensive_computation();
2921
- let result = comm:: recv(port );
2935
+ let result = port. recv();
2922
2936
~~~~
2923
2937
2924
2938
## Creating a task with a bi-directional communication path
@@ -2934,12 +2948,13 @@ the string in response. The child terminates when `0` is received.
2934
2948
Here is the function which implements the child task:
2935
2949
2936
2950
~~~~
2937
- fn stringifier(from_parent: comm::port<uint>,
2938
- to_parent: comm::chan<str>) {
2951
+ # import comm::{port, chan, methods};
2952
+ fn stringifier(from_parent: port<uint>,
2953
+ to_parent: chan<str>) {
2939
2954
let mut value: uint;
2940
2955
loop {
2941
- value = comm:: recv(from_parent );
2942
- comm:: send(to_parent, uint::to_str(value, 10u));
2956
+ value = from_parent. recv();
2957
+ to_parent. send(uint::to_str(value, 10u));
2943
2958
if value == 0u { break; }
2944
2959
}
2945
2960
}
@@ -2956,25 +2971,32 @@ simply the strified version of the received value,
2956
2971
Here is the code for the parent task:
2957
2972
2958
2973
~~~~
2974
+ # import task::{spawn_listener};
2975
+ # import comm::{chan, port, methods};
2959
2976
# fn stringifier(from_parent: comm::port<uint>,
2960
2977
# to_parent: comm::chan<str>) {
2961
2978
# comm::send(to_parent, "22");
2962
2979
# comm::send(to_parent, "23");
2963
2980
# comm::send(to_parent, "0");
2964
2981
# }
2965
- fn main() {
2966
- let from_child = comm::port();
2967
- let to_parent = comm::chan(from_child);
2968
- let to_child = do task::spawn_listener |from_parent| {
2969
- stringifier(from_parent, to_parent);
2970
- };
2971
- comm::send(to_child, 22u);
2972
- assert comm::recv(from_child) == "22";
2973
- comm::send(to_child, 23u);
2974
- assert comm::recv(from_child) == "23";
2975
- comm::send(to_child, 0u);
2976
- assert comm::recv(from_child) == "0";
2977
- }
2982
+ # fn main() {
2983
+
2984
+ let from_child = port();
2985
+ let to_parent = from_child.chan();
2986
+ let to_child = do spawn_listener |from_parent| {
2987
+ stringifier(from_parent, to_parent);
2988
+ };
2989
+
2990
+ to_child.send(22u);
2991
+ assert from_child.recv() == "22";
2992
+
2993
+ to_child.send(23u);
2994
+ assert from_child.recv() == "23";
2995
+
2996
+ to_child.send(0u);
2997
+ assert from_child.recv() == "0";
2998
+
2999
+ # }
2978
3000
~~~~
2979
3001
2980
3002
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
2986
3008
`to_parent` channel in its environment, so both parent and child
2987
3009
can send and receive data to and from the other.
2988
3010
2989
- ## The supervisor relationship
2990
-
2991
- By default, failures in Rust propagate upward through the task tree.
2992
- We say that each task is supervised by its parent, meaning that if the
2993
- task fails, that failure is propagated to the parent task, which will
2994
- fail sometime later. This propagation can be disabled by using the
2995
- function `task::unsupervise()`, which disables error propagation from
2996
- the current task to its parent.
2997
-
2998
3011
# Testing
2999
3012
3000
3013
The Rust language has a facility for testing built into the language.
0 commit comments