@@ -48,8 +48,8 @@ concurrency at this writing:
48
48
* [ ` std::task ` ] - All code relating to tasks and task scheduling,
49
49
* [ ` std::comm ` ] - The message passing interface,
50
50
* [ ` sync::DuplexStream ` ] - An extension of ` pipes::stream ` that allows both sending and receiving,
51
- * [ ` sync::SyncSender ` ] - An extension of ` pipes::stream ` that provides synchronous message sending,
52
- * [ ` sync::SyncReceiver ` ] - An extension of ` pipes::stream ` that acknowledges each message received,
51
+ * [ ` sync::SyncChan ` ] - An extension of ` pipes::stream ` that provides synchronous message sending,
52
+ * [ ` sync::SyncPort ` ] - An extension of ` pipes::stream ` that acknowledges each message received,
53
53
* [ ` sync::rendezvous ` ] - Creates a stream whose channel, upon sending a message, blocks until the
54
54
message is received.
55
55
* [ ` sync::Arc ` ] - The Arc (atomically reference counted) type, for safely sharing immutable data,
@@ -70,8 +70,8 @@ concurrency at this writing:
70
70
[ `std::task` ] : std/task/index.html
71
71
[ `std::comm` ] : std/comm/index.html
72
72
[ `sync::DuplexStream` ] : sync/struct.DuplexStream.html
73
- [ `sync::SyncSender ` ] : sync/struct.SyncSender .html
74
- [ `sync::SyncReceiver ` ] : sync/struct.SyncReceiver .html
73
+ [ `sync::SyncChan ` ] : sync/struct.SyncChan .html
74
+ [ `sync::SyncPort ` ] : sync/struct.SyncPort .html
75
75
[ `sync::rendezvous` ] : sync/fn.rendezvous.html
76
76
[ `sync::Arc` ] : sync/struct.Arc.html
77
77
[ `sync::RWArc` ] : sync/struct.RWArc.html
@@ -141,115 +141,118 @@ receiving messages. Pipes are low-level communication building-blocks and so
141
141
come in a variety of forms, each one appropriate for a different use case. In
142
142
what follows, we cover the most commonly used varieties.
143
143
144
- The simplest way to create a pipe is to use the ` channel `
145
- function to create a ` (Sender, Receiver ) ` pair. In Rust parlance, a * sender *
146
- is a sending endpoint of a pipe, and a * receiver * is the receiving
144
+ The simplest way to create a pipe is to use ` Chan::new `
145
+ function to create a ` (Port, Chan ) ` pair. In Rust parlance, a * channel *
146
+ is a sending endpoint of a pipe, and a * port * is the receiving
147
147
endpoint. Consider the following example of calculating two results
148
148
concurrently:
149
149
150
150
~~~~
151
151
# use std::task::spawn;
152
152
153
- let (tx, rx ): (Sender <int>, Receiver <int>) = channel ();
153
+ let (port, chan ): (Port <int>, Chan <int>) = Chan::new ();
154
154
155
155
spawn(proc() {
156
156
let result = some_expensive_computation();
157
- tx .send(result);
157
+ chan .send(result);
158
158
});
159
159
160
160
some_other_expensive_computation();
161
- let result = rx .recv();
161
+ let result = port .recv();
162
162
# fn some_expensive_computation() -> int { 42 }
163
163
# fn some_other_expensive_computation() {}
164
164
~~~~
165
165
166
166
Let's examine this example in detail. First, the ` let ` statement creates a
167
167
stream for sending and receiving integers (the left-hand side of the ` let ` ,
168
- ` (tx, rx ) ` , is an example of a * destructuring let* : the pattern separates
168
+ ` (chan, port ) ` , is an example of a * destructuring let* : the pattern separates
169
169
a tuple into its component parts).
170
170
171
171
~~~~
172
- let (tx, rx ): (Sender <int>, Receiver <int>) = channel ();
172
+ let (port, chan ): (Port <int>, Chan <int>) = Chan::new ();
173
173
~~~~
174
174
175
- The child task will use the sender to send data to the parent task,
176
- which will wait to receive the data on the receiver . The next statement
175
+ The child task will use the channel to send data to the parent task,
176
+ which will wait to receive the data on the port . The next statement
177
177
spawns the child task.
178
178
179
179
~~~~
180
180
# use std::task::spawn;
181
181
# fn some_expensive_computation() -> int { 42 }
182
- # let (tx, rx ) = channel ();
182
+ # let (port, chan ) = Chan::new ();
183
183
spawn(proc() {
184
184
let result = some_expensive_computation();
185
- tx .send(result);
185
+ chan .send(result);
186
186
});
187
187
~~~~
188
188
189
- Notice that the creation of the task closure transfers ` tx ` to the child
190
- task implicitly: the closure captures ` tx ` in its environment. Both ` Sender `
191
- and ` Receiver ` are sendable types and may be captured into tasks or otherwise
189
+ Notice that the creation of the task closure transfers ` chan ` to the child
190
+ task implicitly: the closure captures ` chan ` in its environment. Both ` Chan `
191
+ and ` Port ` are sendable types and may be captured into tasks or otherwise
192
192
transferred between them. In the example, the child task runs an expensive
193
193
computation, then sends the result over the captured channel.
194
194
195
195
Finally, the parent continues with some other expensive
196
196
computation, then waits for the child's result to arrive on the
197
- receiver :
197
+ port :
198
198
199
199
~~~~
200
200
# fn some_other_expensive_computation() {}
201
- # let (tx, rx ) = channel ::<int>();
202
- # tx .send(0);
201
+ # let (port, chan ) = Chan ::<int>::new ();
202
+ # chan .send(0);
203
203
some_other_expensive_computation();
204
- let result = rx .recv();
204
+ let result = port .recv();
205
205
~~~~
206
206
207
- The ` Sender ` and ` Receiver ` pair created by ` channel ` enables efficient
207
+ The ` Port ` and ` Chan ` pair created by ` Chan::new ` enables efficient
208
208
communication between a single sender and a single receiver, but multiple
209
- senders cannot use a single ` Sender ` value , and multiple receivers cannot use a
210
- single ` Receiver ` value . What if our example needed to compute multiple
211
- results across a number of tasks? The following program is ill-typed:
209
+ senders cannot use a single ` Chan ` , and multiple receivers cannot use a single
210
+ ` Port ` . What if our example needed to compute multiple results across a number
211
+ of tasks? The following program is ill-typed:
212
212
213
213
~~~ {.ignore}
214
+ # use std::task::{spawn};
214
215
# fn some_expensive_computation() -> int { 42 }
215
- let (tx, rx ) = channel ();
216
+ let (port, chan ) = Chan::new ();
216
217
217
218
spawn(proc() {
218
- tx .send(some_expensive_computation());
219
+ chan .send(some_expensive_computation());
219
220
});
220
221
221
- // ERROR! The previous spawn statement already owns the sender ,
222
+ // ERROR! The previous spawn statement already owns the channel ,
222
223
// so the compiler will not allow it to be captured again
223
224
spawn(proc() {
224
- tx .send(some_expensive_computation());
225
+ chan .send(some_expensive_computation());
225
226
});
226
227
~~~
227
228
228
- Instead we can clone the ` tx ` , which allows for multiple senders.
229
+ Instead we can clone the ` chan ` , which allows for multiple senders.
229
230
230
231
~~~
231
- let (tx, rx) = channel();
232
+ # use std::task::spawn;
233
+
234
+ let (port, chan) = Chan::new();
232
235
233
236
for init_val in range(0u, 3) {
234
237
// Create a new channel handle to distribute to the child task
235
- let child_tx = tx .clone();
238
+ let child_chan = chan .clone();
236
239
spawn(proc() {
237
- child_tx .send(some_expensive_computation(init_val));
240
+ child_chan .send(some_expensive_computation(init_val));
238
241
});
239
242
}
240
243
241
- let result = rx .recv() + rx .recv() + rx .recv();
244
+ let result = port .recv() + port .recv() + port .recv();
242
245
# fn some_expensive_computation(_i: uint) -> int { 42 }
243
246
~~~
244
247
245
- Cloning a ` Sender ` produces a new handle to the same channel, allowing multiple
246
- tasks to send data to a single receiver . It upgrades the channel internally in
248
+ Cloning a ` Chan ` produces a new handle to the same channel, allowing multiple
249
+ tasks to send data to a single port . It also upgrades the channel internally in
247
250
order to allow this functionality, which means that channels that are not
248
251
cloned can avoid the overhead required to handle multiple senders. But this
249
252
fact has no bearing on the channel's usage: the upgrade is transparent.
250
253
251
254
Note that the above cloning example is somewhat contrived since
252
- you could also simply use three ` Sender ` pairs, but it serves to
255
+ you could also simply use three ` Chan ` pairs, but it serves to
253
256
illustrate the point. For reference, written with multiple streams, it
254
257
might look like the example below.
255
258
@@ -258,16 +261,16 @@ might look like the example below.
258
261
# use std::vec;
259
262
260
263
// Create a vector of ports, one for each child task
261
- let rxs = vec::from_fn(3, |init_val| {
262
- let (tx, rx ) = channel ();
264
+ let ports = vec::from_fn(3, |init_val| {
265
+ let (port, chan ) = Chan::new ();
263
266
spawn(proc() {
264
- tx .send(some_expensive_computation(init_val));
267
+ chan .send(some_expensive_computation(init_val));
265
268
});
266
- rx
269
+ port
267
270
});
268
271
269
272
// Wait on each port, accumulating the results
270
- let result = rxs .iter().fold(0, |accum, rx | accum + rx .recv() );
273
+ let result = ports .iter().fold(0, |accum, port | accum + port .recv() );
271
274
# fn some_expensive_computation(_i: uint) -> int { 42 }
272
275
~~~
273
276
@@ -278,7 +281,7 @@ later.
278
281
The basic example below illustrates this.
279
282
280
283
~~~
281
- extern crate sync;
284
+ # extern crate sync;
282
285
283
286
# fn main() {
284
287
# fn make_a_sandwich() {};
@@ -339,10 +342,9 @@ Here is a small example showing how to use Arcs. We wish to run concurrently sev
339
342
a single large vector of floats. Each task needs the full vector to perform its duty.
340
343
341
344
~~~
342
- extern crate rand;
343
- extern crate sync;
344
-
345
- use std::vec;
345
+ # extern crate sync;
346
+ extern crate rand;
347
+ # use std::vec;
346
348
use sync::Arc;
347
349
348
350
fn pnorm(nums: &~[f64], p: uint) -> f64 {
@@ -356,11 +358,11 @@ fn main() {
356
358
let numbers_arc = Arc::new(numbers);
357
359
358
360
for num in range(1u, 10) {
359
- let (tx, rx) = channel ();
360
- tx .send(numbers_arc.clone());
361
+ let (port, chan) = Chan::new ();
362
+ chan .send(numbers_arc.clone());
361
363
362
364
spawn(proc() {
363
- let local_arc : Arc<~[f64]> = rx .recv();
365
+ let local_arc : Arc<~[f64]> = port .recv();
364
366
let task_numbers = local_arc.get();
365
367
println!("{}-norm = {}", num, pnorm(task_numbers, num));
366
368
});
@@ -393,8 +395,8 @@ and a clone of it is sent to each task
393
395
# fn main() {
394
396
# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
395
397
# let numbers_arc = Arc::new(numbers);
396
- # let (tx, rx) = channel ();
397
- tx .send(numbers_arc.clone());
398
+ # let (port, chan) = Chan::new ();
399
+ chan .send(numbers_arc.clone());
398
400
# }
399
401
~~~
400
402
@@ -410,9 +412,9 @@ Each task recovers the underlying data by
410
412
# fn main() {
411
413
# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
412
414
# let numbers_arc=Arc::new(numbers);
413
- # let (tx, rx) = channel ();
414
- # tx .send(numbers_arc.clone());
415
- # let local_arc : Arc<~[f64]> = rx .recv();
415
+ # let (port, chan) = Chan::new ();
416
+ # chan .send(numbers_arc.clone());
417
+ # let local_arc : Arc<~[f64]> = port .recv();
416
418
let task_numbers = local_arc.get();
417
419
# }
418
420
~~~
@@ -484,18 +486,19 @@ proceed).
484
486
485
487
A very common thing to do is to spawn a child task where the parent
486
488
and child both need to exchange messages with each other. The
487
- function ` sync::comm::duplex ` supports this pattern. We'll
489
+ function ` sync::comm::DuplexStream() ` supports this pattern. We'll
488
490
look briefly at how to use it.
489
491
490
- To see how ` duplex ` works, we will create a child task
492
+ To see how ` DuplexStream() ` works, we will create a child task
491
493
that repeatedly receives a ` uint ` message, converts it to a string, and sends
492
494
the string in response. The child terminates when it receives ` 0 ` .
493
495
Here is the function that implements the child task:
494
496
495
497
~~~
496
- extern crate sync;
498
+ # extern crate sync;
497
499
# fn main() {
498
- fn stringifier(channel: &sync::DuplexStream<~str, uint>) {
500
+ # use sync::DuplexStream;
501
+ fn stringifier(channel: &DuplexStream<~str, uint>) {
499
502
let mut value: uint;
500
503
loop {
501
504
value = channel.recv();
@@ -517,10 +520,10 @@ response itself is simply the stringified version of the received value,
517
520
Here is the code for the parent task:
518
521
519
522
~~~
520
- extern crate sync;
523
+ # extern crate sync;
521
524
# use std::task::spawn;
522
525
# use sync::DuplexStream;
523
- # fn stringifier(channel: &sync:: DuplexStream<~ str, uint>) {
526
+ # fn stringifier(channel: &DuplexStream<~ str, uint>) {
524
527
# let mut value: uint;
525
528
# loop {
526
529
# value = channel.recv();
@@ -530,7 +533,7 @@ extern crate sync;
530
533
# }
531
534
# fn main() {
532
535
533
- let (from_child, to_child) = sync::duplex ();
536
+ let (from_child, to_child) = DuplexStream::new ();
534
537
535
538
spawn(proc() {
536
539
stringifier(&to_child);
0 commit comments