mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 06:44:35 +00:00
core: New task API
This commit is contained in:
parent
fbc95ba018
commit
4220dcf1e9
@ -2375,10 +2375,10 @@ module `task`. Let's begin with the simplest one, `task::spawn()`:
|
||||
|
||||
~~~~
|
||||
let some_value = 22;
|
||||
let child_task = task::spawn {||
|
||||
task::spawn {||
|
||||
std::io::println("This executes in the child task.");
|
||||
std::io::println(#fmt("%d", some_value));
|
||||
};
|
||||
}
|
||||
~~~~
|
||||
|
||||
The argument to `task::spawn()` is a [unique
|
||||
@ -2456,70 +2456,66 @@ let result = comm::recv(port);
|
||||
## Creating a task with a bi-directional communication path
|
||||
|
||||
A very common thing to do is to spawn a child task where the parent
|
||||
and child both need to exchange messages with each other. The function
|
||||
`task::spawn_connected()` supports this pattern. We'll look briefly at
|
||||
how it is used.
|
||||
and child both need to exchange messages with each
|
||||
other. The function `task::spawn_listener()` supports this pattern. We'll look
|
||||
briefly at how it is used.
|
||||
|
||||
To see how `spawn_connected()` works, we will create a child task
|
||||
To see how `spawn_listener()` works, we will create a child task
|
||||
which receives `uint` messages, converts them to a string, and sends
|
||||
the string in response. The child terminates when `0` is received.
|
||||
Here is the function which implements the child task:
|
||||
|
||||
~~~~
|
||||
fn stringifier(from_par: comm::port<uint>,
|
||||
to_par: comm::chan<str>) {
|
||||
fn stringifier(from_parent: comm::port<uint>,
|
||||
to_parent: comm::chan<str>) {
|
||||
let value: uint;
|
||||
do {
|
||||
value = comm::recv(from_par);
|
||||
comm::send(to_par, uint::to_str(value, 10u));
|
||||
value = comm::recv(from_parent);
|
||||
comm::send(to_parent, uint::to_str(value, 10u));
|
||||
} while value != 0u;
|
||||
}
|
||||
|
||||
~~~~
|
||||
|
||||
You can see that the function takes two parameters. The first is a
|
||||
port used to receive messages from the parent, and the second is a
|
||||
channel used to send messages to the parent. The body itself simply
|
||||
loops, reading from the `from_par` port and then sending its response
|
||||
to the `to_par` channel. The actual response itself is simply the
|
||||
strified version of the received value, `uint::to_str(value)`.
|
||||
|
||||
|
||||
Here is the code for the parent task:
|
||||
|
||||
~~~~
|
||||
# fn stringifier(from_par: comm::port<uint>,
|
||||
# to_par: comm::chan<str>) {
|
||||
# comm::send(to_par, "22");
|
||||
# comm::send(to_par, "23");
|
||||
# comm::send(to_par, "0");
|
||||
# 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 t = task::spawn_connected(stringifier);
|
||||
comm::send(t.to_child, 22u);
|
||||
assert comm::recv(t.from_child) == "22";
|
||||
comm::send(t.to_child, 23u);
|
||||
assert comm::recv(t.from_child) == "23";
|
||||
comm::send(t.to_child, 0u);
|
||||
assert comm::recv(t.from_child) == "0";
|
||||
let from_child = comm::port();
|
||||
let to_parent = comm::chan(from_child);
|
||||
let to_child = 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";
|
||||
}
|
||||
~~~~
|
||||
|
||||
The call to `spawn_connected()` on the first line will instantiate the
|
||||
various ports and channels and startup the child task. The returned
|
||||
value, `t`, is a record of type `task::connected_task<uint,str>`. In
|
||||
addition to the task id of the child, this record defines two fields,
|
||||
`from_child` and `to_child`, which contain the port and channel
|
||||
respectively for communicating with the child. Those fields are used
|
||||
here to send and receive three messages from the child task.
|
||||
|
||||
## Joining a task
|
||||
|
||||
The function `spawn_joinable()` is used to spawn a task that can later
|
||||
be joined. This is implemented by having the child task send a message
|
||||
when it has completed (either successfully or by failing). Therefore,
|
||||
`spawn_joinable()` returns a structure containing both the task ID and
|
||||
the port where this message will be sent---this structure type is
|
||||
called `task::joinable_task`. The structure can be passed to
|
||||
`task::join()`, which simply blocks on the port, waiting to receive
|
||||
the message from the child task.
|
||||
The parent first sets up a port to receive data from and a channel
|
||||
that the child can use to send data to that port. The call to
|
||||
`spawn_listener()` will spawn the child task, providing it with a port
|
||||
on which to receive data from its parent, and returning to the parent
|
||||
the associated channel. Finally, the closure passed to
|
||||
`spawn_listener()` that forms the body of the child task captures the
|
||||
`to_parent` channel in its environment, so both parent and child
|
||||
can send and receive data to and from the other.
|
||||
|
||||
## The supervisor relationship
|
||||
|
||||
|
@ -143,8 +143,6 @@ fn monitor(f: fn~(diagnostic::emitter)) {
|
||||
|
||||
alt task::try {||
|
||||
|
||||
task::unsupervise();
|
||||
|
||||
// The 'diagnostics emitter'. Every error, warning, etc. should
|
||||
// go through this function.
|
||||
let demitter = fn@(cmsp: option<(codemap::codemap, codemap::span)>,
|
||||
|
@ -54,11 +54,11 @@ fn run(lib_path: str, prog: str, args: [str],
|
||||
writeclose(pipe_in.out, input);
|
||||
let p = comm::port();
|
||||
let ch = comm::chan(p);
|
||||
task::spawn_sched(1u) {||
|
||||
task::spawn_sched(task::single_threaded) {||
|
||||
let errput = readclose(pipe_err.in);
|
||||
comm::send(ch, (2, errput));
|
||||
};
|
||||
task::spawn_sched(1u) {||
|
||||
task::spawn_sched(task::single_threaded) {||
|
||||
let output = readclose(pipe_out.in);
|
||||
comm::send(ch, (1, output));
|
||||
};
|
||||
|
@ -35,8 +35,9 @@ enum rust_port {}
|
||||
|
||||
#[abi = "cdecl"]
|
||||
native mod rustrt {
|
||||
fn get_task_id() -> task_id;
|
||||
fn chan_id_send<T: send>(t: *sys::type_desc,
|
||||
target_task: task::task, target_port: port_id,
|
||||
target_task: task_id, target_port: port_id,
|
||||
data: T) -> ctypes::uintptr_t;
|
||||
|
||||
fn new_port(unit_sz: ctypes::size_t) -> *rust_port;
|
||||
@ -58,6 +59,7 @@ native mod rusti {
|
||||
fn call_with_retptr<T: send>(&&f: fn@(*uint)) -> T;
|
||||
}
|
||||
|
||||
type task_id = int;
|
||||
type port_id = int;
|
||||
|
||||
// It's critical that this only have one variant, so it has a record
|
||||
@ -75,7 +77,7 @@ type port_id = int;
|
||||
over other channels."
|
||||
)]
|
||||
enum chan<T: send> {
|
||||
chan_t(task::task, port_id)
|
||||
chan_t(task_id, port_id)
|
||||
}
|
||||
|
||||
resource port_ptr<T: send>(po: *rust_port) {
|
||||
@ -208,7 +210,7 @@ fn peek<T: send>(p: port<T>) -> bool {
|
||||
port used to construct it."
|
||||
)]
|
||||
fn chan<T: send>(p: port<T>) -> chan<T> {
|
||||
chan_t(task::get_task(), rustrt::get_port_id(***p))
|
||||
chan_t(rustrt::get_task_id(), rustrt::get_port_id(***p))
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
1345
src/libcore/task.rs
1345
src/libcore/task.rs
File diff suppressed because it is too large
Load Diff
@ -1929,16 +1929,10 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
// FIXME: Windows can't undwind
|
||||
#[should_fail]
|
||||
#[ignore(cfg(target_os = "win32"))]
|
||||
fn test_init_empty() {
|
||||
|
||||
let r = task::join(
|
||||
task::spawn_joinable {||
|
||||
task::unsupervise();
|
||||
init::<int>([]);
|
||||
});
|
||||
assert r == task::tr_failure
|
||||
init::<int>([]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -316,13 +316,12 @@ fn run_test(+test: test_desc, monitor_ch: comm::chan<monitor_msg>) {
|
||||
task::spawn {||
|
||||
|
||||
let testfn = test.fn;
|
||||
let test_task = task::spawn_joinable {||
|
||||
configure_test_task();
|
||||
testfn();
|
||||
};
|
||||
|
||||
let task_result = task::join(test_task);
|
||||
let test_result = calc_result(test, task_result == task::tr_success);
|
||||
let builder = task::mk_task_builder();
|
||||
let result_future = task::future_result(builder);
|
||||
task::unsupervise(builder);
|
||||
task::run(builder, testfn);
|
||||
let task_result = future::get(result_future);
|
||||
let test_result = calc_result(test, task_result == task::success);
|
||||
comm::send(monitor_ch, (test, test_result));
|
||||
};
|
||||
}
|
||||
@ -337,13 +336,6 @@ fn calc_result(test: test_desc, task_succeeded: bool) -> test_result {
|
||||
}
|
||||
}
|
||||
|
||||
// Call from within a test task to make sure it's set up correctly
|
||||
fn configure_test_task() {
|
||||
// If this task fails we don't want that failure to propagate to the
|
||||
// test runner or else we couldn't keep running tests
|
||||
task::unsupervise();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
|
@ -539,6 +539,11 @@ chan_id_send(type_desc *t, rust_task_id target_task_id,
|
||||
// FIXME: make sure this is thread-safe
|
||||
bool sent = false;
|
||||
rust_task *task = rust_task_thread::get_task();
|
||||
|
||||
LOG(task, comm, "chan_id_send task: 0x%" PRIxPTR
|
||||
" port: 0x%" PRIxPTR, (uintptr_t) target_task_id,
|
||||
(uintptr_t) target_port_id);
|
||||
|
||||
rust_task *target_task = task->kernel->get_task_by_id(target_task_id);
|
||||
if(target_task) {
|
||||
rust_port *port = target_task->get_port_by_id(target_port_id);
|
||||
@ -547,8 +552,12 @@ chan_id_send(type_desc *t, rust_task_id target_task_id,
|
||||
scoped_lock with(target_task->lock);
|
||||
port->deref();
|
||||
sent = true;
|
||||
} else {
|
||||
LOG(task, comm, "didn't get the port");
|
||||
}
|
||||
target_task->deref();
|
||||
} else {
|
||||
LOG(task, comm, "didn't get the task");
|
||||
}
|
||||
return (uintptr_t)sent;
|
||||
}
|
||||
|
@ -28,22 +28,28 @@ fn server(requests: comm::port<request>, responses: comm::chan<uint>) {
|
||||
}
|
||||
|
||||
fn run(args: [str]) {
|
||||
let server = task::spawn_connected(server);
|
||||
let from_child = comm::port();
|
||||
let to_parent = comm::chan(from_child);
|
||||
let to_child = task::spawn_listener {|po|
|
||||
server(po, to_parent);
|
||||
};
|
||||
let size = uint::from_str(args[1]);
|
||||
let workers = uint::from_str(args[2]);
|
||||
let start = std::time::precise_time_s();
|
||||
let to_child = server.to_child;
|
||||
let worker_tasks = [];
|
||||
let to_child = to_child;
|
||||
let worker_results = [];
|
||||
uint::range(0u, workers) {|_i|
|
||||
worker_tasks += [task::spawn_joinable {||
|
||||
let builder = task::mk_task_builder();
|
||||
worker_results += [task::future_result(builder)];
|
||||
task::run(builder) {||
|
||||
uint::range(0u, size / workers) {|_i|
|
||||
comm::send(to_child, bytes(100u));
|
||||
}
|
||||
}];
|
||||
};
|
||||
}
|
||||
vec::iter(worker_tasks) {|t| task::join(t); }
|
||||
comm::send(server.to_child, stop);
|
||||
let result = comm::recv(server.from_child);
|
||||
vec::iter(worker_results) {|r| future::get(r); }
|
||||
comm::send(to_child, stop);
|
||||
let result = comm::recv(from_child);
|
||||
let end = std::time::precise_time_s();
|
||||
let elapsed = end - start;
|
||||
std::io::stdout().write_str(#fmt("Count is %?\n", result));
|
||||
|
@ -69,11 +69,13 @@ fn stress_task(&&id: int) {
|
||||
}
|
||||
|
||||
fn stress(num_tasks: int) {
|
||||
let tasks = [];
|
||||
let results = [];
|
||||
range(0, num_tasks) {|i|
|
||||
tasks += [task::spawn_joinable {|| stress_task(i); }];
|
||||
let builder = task::mk_task_builder();
|
||||
results += [task::future_result(builder)];
|
||||
task::run(builder) {|| stress_task(i); }
|
||||
}
|
||||
for t in tasks { task::join(t); }
|
||||
for r in results { future::get(r); }
|
||||
}
|
||||
|
||||
fn main(argv: [str]) {
|
||||
|
@ -10,7 +10,7 @@ fn start(+token: int) {
|
||||
let ch = iter::foldl(bind int::range(2, n_threads + 1, _),
|
||||
comm::chan(p)) { |ch, i|
|
||||
let id = n_threads + 2 - i;
|
||||
let {to_child, _} = task::spawn_connected::<int, int> {|p, _ch|
|
||||
let to_child = task::spawn_listener::<int> {|p|
|
||||
roundtrip(id, p, ch)
|
||||
};
|
||||
to_child
|
||||
|
@ -7,7 +7,7 @@ import str;
|
||||
fn f(&&n: uint) {
|
||||
let i = 0u;
|
||||
while i < n {
|
||||
task::join(task::spawn_joinable {|| g(); });
|
||||
task::try {|| g() };
|
||||
i += 1u;
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ import option::{some, none};
|
||||
import std::{map, io, time};
|
||||
import io::reader_util;
|
||||
|
||||
import task::joinable_task;
|
||||
import comm::chan;
|
||||
import comm::port;
|
||||
import comm::recv;
|
||||
@ -59,12 +58,14 @@ mod map_reduce {
|
||||
enum reduce_proto { emit_val(int), done, ref, release, }
|
||||
|
||||
fn start_mappers(ctrl: chan<ctrl_proto>, -inputs: [str]) ->
|
||||
[joinable_task] {
|
||||
let tasks = [];
|
||||
[future::future<task::task_result>] {
|
||||
let results = [];
|
||||
for i: str in inputs {
|
||||
tasks += [task::spawn_joinable {|| map_task(ctrl, i)}];
|
||||
let builder = task::mk_task_builder();
|
||||
results += [task::future_result(builder)];
|
||||
task::run(builder) {|| map_task(ctrl, i)}
|
||||
}
|
||||
ret tasks;
|
||||
ret results;
|
||||
}
|
||||
|
||||
fn map_task(ctrl: chan<ctrl_proto>, input: str) {
|
||||
@ -137,7 +138,7 @@ mod map_reduce {
|
||||
reducers = map::new_str_hash();
|
||||
|
||||
let num_mappers = vec::len(inputs) as int;
|
||||
let tasks = start_mappers(chan(ctrl), inputs);
|
||||
let results = start_mappers(chan(ctrl), inputs);
|
||||
|
||||
while num_mappers > 0 {
|
||||
alt recv(ctrl) {
|
||||
@ -158,8 +159,9 @@ mod map_reduce {
|
||||
// log(error, "creating new reducer for " + k);
|
||||
let p = port();
|
||||
let ch = chan(p);
|
||||
tasks +=
|
||||
[task::spawn_joinable{||reduce_task(k, ch)}];
|
||||
let builder = task::mk_task_builder();
|
||||
results += [task::future_result(builder)];
|
||||
task::run(builder) {||reduce_task(k, ch)}
|
||||
c = recv(p);
|
||||
reducers.insert(k, c);
|
||||
}
|
||||
@ -171,7 +173,7 @@ mod map_reduce {
|
||||
|
||||
reducers.values {|v| send(v, done); }
|
||||
|
||||
for t in tasks { task::join(t); }
|
||||
for r in results { future::get(r); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,16 +96,6 @@ fn test_ptr() unsafe {
|
||||
assert p1 >= p2;
|
||||
}
|
||||
|
||||
fn test_task() {
|
||||
fn f() { }
|
||||
let f1 = f, f2 = f;
|
||||
let t1 = task::spawn {|| f1(); };
|
||||
let t2 = task::spawn {|| f2(); };
|
||||
|
||||
assert (t1 == t1);
|
||||
assert (t1 != t2);
|
||||
}
|
||||
|
||||
fn test_fn() {
|
||||
fn f() { }
|
||||
fn g() { }
|
||||
@ -147,7 +137,6 @@ fn main() {
|
||||
test_port();
|
||||
test_chan();
|
||||
test_ptr();
|
||||
test_task();
|
||||
test_fn();
|
||||
test_native_fn();
|
||||
}
|
||||
|
@ -8,7 +8,6 @@
|
||||
use std;
|
||||
|
||||
import task;
|
||||
import task::join;
|
||||
import comm;
|
||||
import comm::chan;
|
||||
import comm::send;
|
||||
@ -18,21 +17,18 @@ import comm::recv;
|
||||
fn grandchild(c: chan<int>) { send(c, 42); }
|
||||
|
||||
fn child(c: chan<int>) {
|
||||
let _grandchild = task::spawn_joinable {|| grandchild(c); };
|
||||
join(_grandchild);
|
||||
task::spawn {|| grandchild(c); }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let p = comm::port();
|
||||
let ch = chan(p);
|
||||
|
||||
let _child = task::spawn_joinable {|| child(ch); };
|
||||
task::spawn {|| child(ch); }
|
||||
|
||||
let x: int = recv(p);
|
||||
|
||||
log(debug, x);
|
||||
|
||||
assert (x == 42);
|
||||
|
||||
join(_child);
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ fn a() {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let t = spawn_joinable {|| a(); };
|
||||
join(t);
|
||||
iter::repeat(100u) {||
|
||||
spawn {|| a(); }
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +0,0 @@
|
||||
// -*- rust -*-
|
||||
|
||||
use std;
|
||||
|
||||
import task::*;
|
||||
|
||||
fn main() {
|
||||
let other = spawn_joinable {|| child(); };
|
||||
#error("1");
|
||||
yield();
|
||||
join(other);
|
||||
#error("3");
|
||||
}
|
||||
|
||||
fn child() { #error("2"); }
|
@ -1,21 +0,0 @@
|
||||
// -*- rust -*-
|
||||
// xfail-win32
|
||||
use std;
|
||||
import task;
|
||||
import comm::port;
|
||||
import comm::recv;
|
||||
|
||||
fn child() { assert (1 == 2); }
|
||||
|
||||
fn parent() {
|
||||
// Since this task isn't supervised it won't bring down the whole
|
||||
// process
|
||||
task::unsupervise();
|
||||
let p = port::<int>();
|
||||
task::spawn {|| child(); };
|
||||
let x = recv(p);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
task::spawn {|| parent(); };
|
||||
}
|
@ -9,12 +9,13 @@ fn die() {
|
||||
}
|
||||
|
||||
fn iloop() {
|
||||
task::unsupervise();
|
||||
task::spawn {|| die(); };
|
||||
}
|
||||
|
||||
fn main() {
|
||||
uint::range(0u, 100u) {|_i|
|
||||
task::spawn {|| iloop(); };
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {|| iloop(); };
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ fn getbig(&&i: int) {
|
||||
fn main() {
|
||||
let sz = 400u;
|
||||
while sz < 500u {
|
||||
task::join(task::spawn_joinable {|| getbig(200) });
|
||||
task::try {|| getbig(200) };
|
||||
sz += 1u;
|
||||
}
|
||||
}
|
@ -61,6 +61,6 @@ fn main() {
|
||||
for f in fns {
|
||||
let sz = rng.next() % 256u32 + 256u32;
|
||||
let frame_backoff = rng.next() % 10u32 + 1u32;
|
||||
task::join(task::spawn_joinable {|| runtest(f, frame_backoff);});
|
||||
task::try {|| runtest(f, frame_backoff) };
|
||||
}
|
||||
}
|
@ -9,7 +9,6 @@ fn die() {
|
||||
}
|
||||
|
||||
fn iloop() {
|
||||
task::unsupervise();
|
||||
task::spawn {|| die(); };
|
||||
let p = comm::port::<()>();
|
||||
let c = comm::chan(p);
|
||||
@ -23,6 +22,8 @@ fn iloop() {
|
||||
|
||||
fn main() {
|
||||
uint::range(0u, 16u) {|_i|
|
||||
task::spawn {|| iloop(); };
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {|| iloop(); }
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
use std;
|
||||
import task::join;
|
||||
import task::spawn_joinable;
|
||||
|
||||
fn main() { let x = spawn_joinable {|| m::child(10); }; join(x); }
|
||||
|
||||
mod m {
|
||||
fn child(&&i: int) { log(debug, i); }
|
||||
}
|
@ -5,8 +5,7 @@ use std;
|
||||
import task;
|
||||
|
||||
fn main() {
|
||||
let t = task::spawn_joinable {|| child(10); };
|
||||
task::join(t);
|
||||
task::spawn {|| child(10); };
|
||||
}
|
||||
|
||||
fn child(&&i: int) { log(error, i); assert (i == 10); }
|
||||
|
@ -1,14 +1,8 @@
|
||||
use std;
|
||||
|
||||
import task::spawn_joinable;
|
||||
import task::join;
|
||||
|
||||
fn main() { test00(); }
|
||||
|
||||
fn start() { #debug("Started / Finished task."); }
|
||||
|
||||
fn test00() {
|
||||
let t = spawn_joinable {|| start(); };
|
||||
join(t);
|
||||
task::try {|| start() };
|
||||
#debug("Completing.");
|
||||
}
|
||||
|
@ -7,7 +7,9 @@ fn start(&&task_number: int) { #debug("Started / Finished task."); }
|
||||
|
||||
fn test00() {
|
||||
let i: int = 0;
|
||||
let t = task::spawn_joinable {|| start(i); };
|
||||
let builder = task::mk_task_builder();
|
||||
let r = task::future_result(builder);
|
||||
task::run(builder) {|| start(i); };
|
||||
|
||||
// Sleep long enough for the task to finish.
|
||||
let i = 0;
|
||||
@ -17,7 +19,7 @@ fn test00() {
|
||||
}
|
||||
|
||||
// Try joining tasks that have already finished.
|
||||
task::join(t);
|
||||
future::get(r);
|
||||
|
||||
#debug("Joined task.");
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ fn main() {
|
||||
#debug("Check that we don't deadlock.");
|
||||
let p = comm::port::<int>();
|
||||
let ch = comm::chan(p);
|
||||
let a = task::spawn_joinable {|| start(ch, 0, 10); };
|
||||
task::join(a);
|
||||
task::try {|| start(ch, 0, 10) };
|
||||
#debug("Joined task");
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
// xfail-win32
|
||||
use std;
|
||||
|
||||
import task;
|
||||
|
||||
fn main() {
|
||||
#debug("===== SPAWNING and JOINING THREAD TASKS =====");
|
||||
test00();
|
||||
}
|
||||
|
||||
fn start(&&task_number: int) {
|
||||
#debug("Started task.");
|
||||
let i: int = 0;
|
||||
while i < 10000 { i = i + 1; }
|
||||
#debug("Finished task.");
|
||||
}
|
||||
|
||||
fn test00() {
|
||||
let number_of_tasks: int = 8;
|
||||
|
||||
let i: int = 0;
|
||||
let tasks = [];
|
||||
while i < number_of_tasks {
|
||||
i = i + 1;
|
||||
tasks += [task::spawn_joinable {|| start(i); }];
|
||||
}
|
||||
|
||||
for t in tasks { task::join(t); }
|
||||
|
||||
#debug("Joined all task.");
|
||||
}
|
@ -30,17 +30,19 @@ fn test00() {
|
||||
let i: int = 0;
|
||||
|
||||
// Create and spawn tasks...
|
||||
let tasks = [];
|
||||
let results = [];
|
||||
while i < number_of_tasks {
|
||||
tasks += [task::spawn_joinable {||
|
||||
let builder = task::mk_task_builder();
|
||||
results += [task::future_result(builder)];
|
||||
task::run(builder) {||
|
||||
test00_start(ch, i, number_of_messages)
|
||||
}];
|
||||
}
|
||||
i = i + 1;
|
||||
}
|
||||
|
||||
// Read from spawned tasks...
|
||||
let sum = 0;
|
||||
for t in tasks {
|
||||
for r in results {
|
||||
i = 0;
|
||||
while i < number_of_messages {
|
||||
let value = recv(po);
|
||||
@ -50,7 +52,7 @@ fn test00() {
|
||||
}
|
||||
|
||||
// Join spawned tasks...
|
||||
for t in tasks { task::join(t); }
|
||||
for r in results { future::get(r); }
|
||||
|
||||
#debug("Completed: Final number is: ");
|
||||
log(error, sum);
|
||||
|
@ -1,9 +1,6 @@
|
||||
use std;
|
||||
import task;
|
||||
import comm;
|
||||
import comm::chan;
|
||||
import comm::recv;
|
||||
import comm::port;
|
||||
|
||||
fn main() { test00(); }
|
||||
|
||||
@ -15,40 +12,35 @@ fn test00_start(c: comm::chan<int>, start: int, number_of_messages: int) {
|
||||
fn test00() {
|
||||
let r: int = 0;
|
||||
let sum: int = 0;
|
||||
let p = port();
|
||||
let p = comm::port();
|
||||
let number_of_messages: int = 10;
|
||||
let c = chan(p);
|
||||
let c = comm::chan(p);
|
||||
|
||||
let t0 = task::spawn_joinable {||
|
||||
task::spawn {||
|
||||
test00_start(c, number_of_messages * 0, number_of_messages);
|
||||
};
|
||||
let t1 = task::spawn_joinable {||
|
||||
}
|
||||
task::spawn {||
|
||||
test00_start(c, number_of_messages * 1, number_of_messages);
|
||||
};
|
||||
let t2 = task::spawn_joinable {||
|
||||
}
|
||||
task::spawn {||
|
||||
test00_start(c, number_of_messages * 2, number_of_messages);
|
||||
};
|
||||
let t3 = task::spawn_joinable {||
|
||||
}
|
||||
task::spawn {||
|
||||
test00_start(c, number_of_messages * 3, number_of_messages);
|
||||
};
|
||||
}
|
||||
|
||||
let i: int = 0;
|
||||
while i < number_of_messages {
|
||||
r = recv(p);
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
r = recv(p);
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
r = recv(p);
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
r = recv(p);
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
task::join(t0);
|
||||
task::join(t1);
|
||||
task::join(t2);
|
||||
task::join(t3);
|
||||
|
||||
assert (sum == number_of_messages * 4 * (number_of_messages * 4 - 1) / 2);
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
use std;
|
||||
import task;
|
||||
import comm;
|
||||
|
||||
fn main() { test00(); }
|
||||
|
||||
fn test00_start(c: comm::chan<int>, start: int, number_of_messages: int) {
|
||||
let i: int = 0;
|
||||
while i < number_of_messages { comm::send(c, start + i); i += 1; }
|
||||
}
|
||||
|
||||
fn test00() {
|
||||
let r: int = 0;
|
||||
let sum: int = 0;
|
||||
let p = comm::port();
|
||||
let c = comm::chan(p);
|
||||
let number_of_messages: int = 10;
|
||||
|
||||
let t0 = task::spawn_joinable {||
|
||||
test00_start(c, number_of_messages * 0, number_of_messages);
|
||||
};
|
||||
let t1 = task::spawn_joinable {||
|
||||
test00_start(c, number_of_messages * 1, number_of_messages);
|
||||
};
|
||||
let t2 = task::spawn_joinable {||
|
||||
test00_start(c, number_of_messages * 2, number_of_messages);
|
||||
};
|
||||
let t3 = task::spawn_joinable {||
|
||||
test00_start(c, number_of_messages * 3, number_of_messages);
|
||||
};
|
||||
|
||||
let i: int = 0;
|
||||
while i < number_of_messages {
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
r = comm::recv(p);
|
||||
sum += r;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
task::join(t0);
|
||||
task::join(t1);
|
||||
task::join(t2);
|
||||
task::join(t3);
|
||||
|
||||
assert (sum == number_of_messages * 4 * (number_of_messages * 4 - 1) / 2);
|
||||
}
|
@ -16,9 +16,11 @@ fn test00() {
|
||||
let number_of_messages: int = 10;
|
||||
let ch = comm::chan(p);
|
||||
|
||||
let t0 = task::spawn_joinable {||
|
||||
let builder = task::mk_task_builder();
|
||||
let r = task::future_result(builder);
|
||||
task::run(builder) {||
|
||||
test00_start(ch, number_of_messages);
|
||||
};
|
||||
}
|
||||
|
||||
let i: int = 0;
|
||||
while i < number_of_messages {
|
||||
@ -27,7 +29,7 @@ fn test00() {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
task::join(t0);
|
||||
future::get(r);
|
||||
|
||||
assert (sum == number_of_messages * (number_of_messages - 1) / 2);
|
||||
}
|
||||
|
@ -38,20 +38,20 @@ fn test00() {
|
||||
|
||||
let i: int = 0;
|
||||
|
||||
let tasks = [];
|
||||
let results = [];
|
||||
while i < number_of_tasks {
|
||||
i = i + 1;
|
||||
tasks += [
|
||||
task::spawn_joinable {|| test00_start(ch, i, number_of_messages);}
|
||||
];
|
||||
let builder = task::mk_task_builder();
|
||||
results += [task::future_result(builder)];
|
||||
task::run(builder) {|| test00_start(ch, i, number_of_messages);}
|
||||
}
|
||||
let sum: int = 0;
|
||||
for t in tasks {
|
||||
for r in results {
|
||||
i = 0;
|
||||
while i < number_of_messages { sum += recv(po); i = i + 1; }
|
||||
}
|
||||
|
||||
for t in tasks { task::join(t); }
|
||||
for r in results { future::get(r); }
|
||||
|
||||
#debug("Completed: Final number is: ");
|
||||
assert (sum ==
|
||||
@ -123,14 +123,16 @@ fn test06() {
|
||||
|
||||
let i: int = 0;
|
||||
|
||||
let tasks = [];
|
||||
let results = [];
|
||||
while i < number_of_tasks {
|
||||
i = i + 1;
|
||||
tasks += [task::spawn_joinable {|| test06_start(i);}];
|
||||
let builder = task::mk_task_builder();
|
||||
results += [task::future_result(builder)];
|
||||
task::run(builder) {|| test06_start(i);};
|
||||
}
|
||||
|
||||
|
||||
for t in tasks { task::join(t); }
|
||||
for r in results { future::get(r); }
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,18 +1,17 @@
|
||||
// xfail-win32
|
||||
// Create a task that is supervised by another task,
|
||||
// join the supervised task from the supervising task,
|
||||
// then fail the supervised task. The supervised task
|
||||
// will kill the supervising task, waking it up. The
|
||||
// supervising task no longer needs to be wakened when
|
||||
// the supervised task exits.
|
||||
|
||||
// Create a task that is supervised by another task, join the supervised task
|
||||
// from the supervising task, then fail the supervised task. The supervised
|
||||
// task will kill the supervising task, waking it up. The supervising task no
|
||||
// longer needs to be wakened when the supervised task exits.
|
||||
|
||||
use std;
|
||||
import task;
|
||||
|
||||
fn supervised() {
|
||||
// Yield to make sure the supervisor joins before we
|
||||
// fail. This is currently not needed because the supervisor
|
||||
// runs first, but I can imagine that changing.
|
||||
// Yield to make sure the supervisor joins before we fail. This is
|
||||
// currently not needed because the supervisor runs first, but I can
|
||||
// imagine that changing.
|
||||
task::yield();
|
||||
fail;
|
||||
}
|
||||
@ -20,15 +19,14 @@ fn supervised() {
|
||||
fn supervisor() {
|
||||
// Unsupervise this task so the process doesn't return a failure status as
|
||||
// a result of the main task being killed.
|
||||
task::unsupervise();
|
||||
let f = supervised;
|
||||
let t = task::spawn_joinable {|| supervised(); };
|
||||
task::join(t);
|
||||
task::try {|| supervised() };
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let dom2 = task::spawn_joinable {|| supervisor(); };
|
||||
task::join(dom2);
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {|| supervisor(); }
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
|
@ -1,18 +0,0 @@
|
||||
fn stringifier(from_par: comm::port<uint>,
|
||||
to_par: comm::chan<str>) {
|
||||
let value: uint;
|
||||
do {
|
||||
value = comm::recv(from_par);
|
||||
comm::send(to_par, uint::to_str(value, 10u));
|
||||
} while value != 0u;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let t = task::spawn_connected(stringifier);
|
||||
comm::send(t.to_child, 22u);
|
||||
assert comm::recv(t.from_child) == "22";
|
||||
comm::send(t.to_child, 23u);
|
||||
assert comm::recv(t.from_child) == "23";
|
||||
comm::send(t.to_child, 0u);
|
||||
assert comm::recv(t.from_child) == "0";
|
||||
}
|
@ -11,14 +11,14 @@ fn test_cont() { let i = 0; while i < 1 { i += 1; let x: @int = cont; } }
|
||||
fn test_ret() { let x: @int = ret; }
|
||||
|
||||
fn test_fail() {
|
||||
fn f() { task::unsupervise(); let x: @int = fail; }
|
||||
task::spawn {|| f(); };
|
||||
fn f() { let x: @int = fail; }
|
||||
task::try {|| f() };
|
||||
}
|
||||
|
||||
fn test_fail_indirect() {
|
||||
fn f() -> ! { fail; }
|
||||
fn g() { task::unsupervise(); let x: @int = f(); }
|
||||
task::spawn {|| g(); };
|
||||
fn g() { let x: @int = f(); }
|
||||
task::try {|| g() };
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
@ -5,8 +5,9 @@
|
||||
// that it doesn't bring down the whole proc
|
||||
|
||||
fn main() {
|
||||
task::spawn {||
|
||||
task::unsupervise();
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {||
|
||||
fn f() { f() };
|
||||
f();
|
||||
};
|
||||
|
@ -3,11 +3,12 @@ use std;
|
||||
import task;
|
||||
|
||||
fn f() {
|
||||
task::unsupervise();
|
||||
let a = @0;
|
||||
fail;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
task::spawn {|| f(); };
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {|| f(); }
|
||||
}
|
@ -8,7 +8,6 @@ resource complainer(c: comm::chan<bool>) {
|
||||
}
|
||||
|
||||
fn f(c: comm::chan<bool>) {
|
||||
task::unsupervise();
|
||||
let c <- complainer(c);
|
||||
fail;
|
||||
}
|
||||
@ -16,6 +15,8 @@ fn f(c: comm::chan<bool>) {
|
||||
fn main() {
|
||||
let p = comm::port();
|
||||
let c = comm::chan(p);
|
||||
task::spawn {|| f(c); };
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {|| f(c); }
|
||||
assert comm::recv(p);
|
||||
}
|
@ -7,11 +7,12 @@ resource complainer(c: @int) {
|
||||
}
|
||||
|
||||
fn f() {
|
||||
task::unsupervise();
|
||||
let c <- complainer(@0);
|
||||
fail;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
task::spawn {|| f(); };
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {|| f(); }
|
||||
}
|
@ -3,11 +3,12 @@ use std;
|
||||
import task;
|
||||
|
||||
fn f() {
|
||||
task::unsupervise();
|
||||
let a = ~0;
|
||||
fail;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
task::spawn {|| f(); };
|
||||
let builder = task::mk_task_builder();
|
||||
task::unsupervise(builder);
|
||||
task::run(builder) {|| f(); }
|
||||
}
|
@ -4,13 +4,15 @@ import task;
|
||||
import task::*;
|
||||
|
||||
fn main() {
|
||||
let other = task::spawn_joinable {|| child(); };
|
||||
let builder = task::mk_task_builder();
|
||||
let result = task::future_result(builder);
|
||||
task::run(builder) {|| child(); }
|
||||
#error("1");
|
||||
yield();
|
||||
#error("2");
|
||||
yield();
|
||||
#error("3");
|
||||
join(other);
|
||||
future::get(result);
|
||||
}
|
||||
|
||||
fn child() {
|
||||
|
@ -4,10 +4,12 @@ import task;
|
||||
import task::*;
|
||||
|
||||
fn main() {
|
||||
let other = task::spawn_joinable {|| child(); };
|
||||
let builder = task::mk_task_builder();
|
||||
let result = task::future_result(builder);
|
||||
task::run(builder) {|| child(); }
|
||||
#error("1");
|
||||
yield();
|
||||
join(other);
|
||||
future::get(result);
|
||||
}
|
||||
|
||||
fn child() { #error("2"); }
|
||||
|
Loading…
Reference in New Issue
Block a user