Merge pull request #3153 from jruderman/sconv

Add spawn_conversation
This commit is contained in:
Ben Blum 2012-08-08 17:05:31 -07:00
commit 35db5b7be1
5 changed files with 67 additions and 51 deletions

View file

@ -40,9 +40,8 @@ unsafe fn chan_from_global_ptr<T: send>(
log(debug,~"is probably zero...");
// There's no global channel. We must make it
let setup_po = comm::port();
let setup_ch = comm::chan(setup_po);
let setup_ch = do task_fn().spawn_listener |setup_po| {
let (setup_po, setup_ch) = do task_fn().spawn_conversation
|setup_po, setup_ch| {
let po = comm::port::<T>();
let ch = comm::chan(po);
comm::send(setup_ch, ch);

View file

@ -52,6 +52,7 @@ export spawn_unlinked;
export spawn_supervised;
export spawn_with;
export spawn_listener;
export spawn_conversation;
export spawn_sched;
export try;
@ -376,6 +377,20 @@ impl task_builder for task_builder {
comm::recv(setup_po)
}
/**
* Runs a new task, setting up communication in both directions
*/
fn spawn_conversation<A: send, B: send>
(+f: fn~(comm::port<A>, comm::chan<B>))
-> (comm::port<B>, comm::chan<A>) {
let from_child = comm::port();
let to_parent = comm::chan(from_child);
let to_child = do self.spawn_listener |from_parent| {
f(from_parent, to_parent)
};
(from_child, to_child)
}
/**
* Execute a function in another task and return either the return value
* of the function or result::err.
@ -474,31 +489,24 @@ fn spawn_listener<A:send>(+f: fn~(comm::port<A>)) -> comm::chan<A> {
/*!
* Runs a new task while providing a channel from the parent to the child
*
* Sets up a communication channel from the current task to the new
* child task, passes the port to child's body, and returns a channel
* linked to the port to the parent.
*
* This encapsulates some boilerplate handshaking logic that would
* otherwise be required to establish communication from the parent
* to the child.
*
* The simplest way to establish bidirectional communication between
* a parent in child is as follows:
*
* let po = comm::port();
* let ch = comm::chan(po);
* let ch = do spawn_listener |po| {
* // Now the child has a port called 'po' to read from and
* // an environment-captured channel called 'ch'.
* };
* // Likewise, the parent has both a 'po' and 'ch'
*
* This function is equivalent to `task().spawn_listener(f)`.
*/
task().spawn_listener(f)
}
fn spawn_conversation<A: send, B: send>
(+f: fn~(comm::port<A>, comm::chan<B>))
-> (comm::port<B>, comm::chan<A>) {
/*!
* Runs a new task, setting up communication in both directions
*
* This function is equivalent to `task().spawn_conversation(f)`.
*/
task().spawn_conversation(f)
}
fn spawn_sched(mode: sched_mode, +f: fn~()) {
/*!
* Creates a new scheduler and executes a task on it
@ -1716,6 +1724,17 @@ fn test_spawn_listiner_bidi() {
assert res == ~"pong";
}
#[test]
fn test_spawn_conversation() {
let (recv_str, send_int) = do spawn_conversation |recv_int, send_str| {
let input = comm::recv(recv_int);
let output = int::str(input);
comm::send(send_str, output);
};
comm::send(send_int, 1);
assert comm::recv(recv_str) == ~"1";
}
#[test]
fn test_try_success() {
match do try {

View file

@ -29,9 +29,8 @@ fn run(
return doc;
}
let result_port = comm::port();
let result_chan = comm::chan(result_port);
let page_chan = do task::spawn_listener |page_port| {
let (result_port, page_chan) = do task::spawn_conversation
|page_port, result_chan| {
comm::send(result_chan, make_doc_from_pages(page_port));
};

View file

@ -28,15 +28,12 @@ fn server(requests: comm::port<request>, responses: comm::chan<uint>) {
}
fn run(args: ~[~str]) {
let from_child = comm::port();
let to_parent = comm::chan(from_child);
let to_child = do task::spawn_listener |po| {
server(po, to_parent);
let (from_child, to_child) = do task::spawn_conversation |po, ch| {
server(po, ch);
};
let size = option::get(uint::from_str(args[1]));
let workers = option::get(uint::from_str(args[2]));
let start = std::time::precise_time_s();
let to_child = to_child;
let mut worker_results = ~[];
for uint::range(0u, workers) |_i| {
do task::task().future_result(|+r| {
@ -65,7 +62,7 @@ fn main(args: ~[~str]) {
~[~"", ~"10000", ~"4"]
} else {
args
};
};
debug!{"%?", args};
run(args);