@@ -39,51 +39,26 @@ data through the global _exchange heap_.
39
39
40
40
While Rust's type system provides the building blocks needed for safe
41
41
and efficient tasks, all of the task functionality itself is implemented
42
- in the standard and sync libraries, which are still under development
42
+ in the standard and extra libraries, which are still under development
43
43
and do not always present a consistent or complete interface.
44
44
45
45
For your reference, these are the standard modules involved in Rust
46
46
concurrency at this writing:
47
47
48
48
* [ ` std::task ` ] - All code relating to tasks and task scheduling,
49
49
* [ ` std::comm ` ] - The message passing interface,
50
- * [ ` sync::DuplexStream ` ] - An extension of ` pipes::stream ` that allows both sending and receiving,
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
- * [ ` sync::rendezvous ` ] - Creates a stream whose channel, upon sending a message, blocks until the
54
- message is received.
55
- * [ ` sync::Arc ` ] - The Arc (atomically reference counted) type, for safely sharing immutable data,
56
- * [ ` sync::RWArc ` ] - A dual-mode Arc protected by a reader-writer lock,
57
- * [ ` sync::MutexArc ` ] - An Arc with mutable data protected by a blocking mutex,
58
- * [ ` sync::Semaphore ` ] - A counting, blocking, bounded-waiting semaphore,
59
- * [ ` sync::Mutex ` ] - A blocking, bounded-waiting, mutual exclusion lock with an associated
60
- FIFO condition variable,
61
- * [ ` sync::RWLock ` ] - A blocking, no-starvation, reader-writer lock with an associated condvar,
62
- * [ ` sync::Barrier ` ] - A barrier enables multiple tasks to synchronize the beginning
63
- of some computation,
64
- * [ ` sync::TaskPool ` ] - A task pool abstraction,
65
- * [ ` sync::Future ` ] - A type encapsulating the result of a computation which may not be complete,
66
- * [ ` sync::one ` ] - A "once initialization" primitive
67
- * [ ` sync::mutex ` ] - A proper mutex implementation regardless of the "flavor of task" which is
68
- acquiring the lock.
50
+ * [ ` extra::comm ` ] - Additional messaging types based on ` std::comm ` ,
51
+ * [ ` extra::sync ` ] - More exotic synchronization tools, including locks,
52
+ * [ ` extra::arc ` ] - The Arc (atomically reference counted) type,
53
+ for safely sharing immutable data,
54
+ * [ ` extra::future ` ] - A type representing values that may be computed concurrently and retrieved at a later time.
69
55
70
56
[ `std::task` ] : std/task/index.html
71
57
[ `std::comm` ] : std/comm/index.html
72
- [ `sync::DuplexStream` ] : sync/struct.DuplexStream.html
73
- [ `sync::SyncChan` ] : sync/struct.SyncChan.html
74
- [ `sync::SyncPort` ] : sync/struct.SyncPort.html
75
- [ `sync::rendezvous` ] : sync/fn.rendezvous.html
76
- [ `sync::Arc` ] : sync/struct.Arc.html
77
- [ `sync::RWArc` ] : sync/struct.RWArc.html
78
- [ `sync::MutexArc` ] : sync/struct.MutexArc.html
79
- [ `sync::Semaphore` ] : sync/struct.Semaphore.html
80
- [ `sync::Mutex` ] : sync/struct.Mutex.html
81
- [ `sync::RWLock` ] : sync/struct.RWLock.html
82
- [ `sync::Barrier` ] : sync/struct.Barrier.html
83
- [ `sync::TaskPool` ] : sync/struct.TaskPool.html
84
- [ `sync::Future` ] : sync/struct.Future.html
85
- [ `sync::one` ] : sync/one/index.html
86
- [ `sync::mutex` ] : sync/mutex/index.html
58
+ [ `extra::comm` ] : extra/comm/index.html
59
+ [ `extra::sync` ] : extra/sync/index.html
60
+ [ `extra::arc` ] : extra/arc/index.html
61
+ [ `extra::future` ] : extra/future/index.html
87
62
88
63
# Basics
89
64
@@ -279,25 +254,21 @@ let result = ports.iter().fold(0, |accum, port| accum + port.recv() );
279
254
~~~
280
255
281
256
## Backgrounding computations: Futures
282
- With ` sync::Future ` , rust has a mechanism for requesting a computation and getting the result
257
+ With ` extra::future ` , rust has a mechanism for requesting a computation and getting the result
283
258
later.
284
259
285
260
The basic example below illustrates this.
286
261
287
262
~~~
288
- # extern mod sync;
289
-
290
- # fn main() {
291
263
# fn make_a_sandwich() {};
292
264
fn fib(n: u64) -> u64 {
293
265
// lengthy computation returning an uint
294
266
12586269025
295
267
}
296
268
297
- let mut delayed_fib = sync ::Future::spawn(proc() fib(50));
269
+ let mut delayed_fib = extra::future ::Future::spawn(proc() fib(50));
298
270
make_a_sandwich();
299
271
println!("fib(50) = {:?}", delayed_fib.get())
300
- # }
301
272
~~~
302
273
303
274
The call to ` future::spawn ` returns immediately a ` future ` object regardless of how long it
@@ -310,7 +281,6 @@ Here is another example showing how futures allow you to background computations
310
281
be distributed on the available cores.
311
282
312
283
~~~
313
- # extern mod sync;
314
284
# use std::vec;
315
285
fn partial_sum(start: uint) -> f64 {
316
286
let mut local_sum = 0f64;
@@ -321,7 +291,7 @@ fn partial_sum(start: uint) -> f64 {
321
291
}
322
292
323
293
fn main() {
324
- let mut futures = vec::from_fn(1000, |ind| sync ::Future::spawn( proc() { partial_sum(ind) }));
294
+ let mut futures = vec::from_fn(1000, |ind| extra::future ::Future::spawn( proc() { partial_sum(ind) }));
325
295
326
296
let mut final_res = 0f64;
327
297
for ft in futures.mut_iter() {
@@ -339,17 +309,16 @@ add up to a significant amount of wasted memory and would require copying the sa
339
309
necessary.
340
310
341
311
To tackle this issue, one can use an Atomically Reference Counted wrapper (` Arc ` ) as implemented in
342
- the ` sync ` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
312
+ the ` extra ` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
343
313
acts as a reference to the shared data and only this reference is shared and cloned.
344
314
345
315
Here is a small example showing how to use Arcs. We wish to run concurrently several computations on
346
316
a single large vector of floats. Each task needs the full vector to perform its duty.
347
317
348
318
~~~
349
- # extern mod sync;
350
319
# use std::vec;
351
320
# use std::rand;
352
- use sync ::Arc;
321
+ use extra::arc ::Arc;
353
322
354
323
fn pnorm(nums: &~[f64], p: uint) -> f64 {
355
324
nums.iter().fold(0.0, |a,b| a+(*b).powf(&(p as f64)) ).powf(&(1.0 / (p as f64)))
@@ -379,48 +348,39 @@ at the power given as argument and takes the inverse power of this value). The A
379
348
created by the line
380
349
381
350
~~~
382
- # extern mod sync;
383
- # use sync::Arc;
351
+ # use extra::arc::Arc;
384
352
# use std::vec;
385
353
# use std::rand;
386
- # fn main() {
387
354
# let numbers = vec::from_fn(1000000, |_| rand::random::<f64>());
388
355
let numbers_arc=Arc::new(numbers);
389
- # }
390
356
~~~
391
357
392
358
and a clone of it is sent to each task
393
359
394
360
~~~
395
- # extern mod sync;
396
- # use sync::Arc;
361
+ # use extra::arc::Arc;
397
362
# use std::vec;
398
363
# use std::rand;
399
- # fn main() {
400
364
# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
401
365
# let numbers_arc = Arc::new(numbers);
402
366
# let (port, chan) = Chan::new();
403
367
chan.send(numbers_arc.clone());
404
- # }
405
368
~~~
406
369
407
370
copying only the wrapper and not its contents.
408
371
409
372
Each task recovers the underlying data by
410
373
411
374
~~~
412
- # extern mod sync;
413
- # use sync::Arc;
375
+ # use extra::arc::Arc;
414
376
# use std::vec;
415
377
# use std::rand;
416
- # fn main() {
417
378
# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
418
379
# let numbers_arc=Arc::new(numbers);
419
380
# let (port, chan) = Chan::new();
420
381
# chan.send(numbers_arc.clone());
421
382
# let local_arc : Arc<~[f64]> = port.recv();
422
383
let task_numbers = local_arc.get();
423
- # }
424
384
~~~
425
385
426
386
and can use it as if it were local.
@@ -490,27 +450,25 @@ proceed).
490
450
491
451
A very common thing to do is to spawn a child task where the parent
492
452
and child both need to exchange messages with each other. The
493
- function ` sync ::comm::DuplexStream()` supports this pattern. We'll
453
+ function ` extra ::comm::DuplexStream()` supports this pattern. We'll
494
454
look briefly at how to use it.
495
455
496
456
To see how ` DuplexStream() ` works, we will create a child task
497
457
that repeatedly receives a ` uint ` message, converts it to a string, and sends
498
458
the string in response. The child terminates when it receives ` 0 ` .
499
459
Here is the function that implements the child task:
500
460
501
- ~~~
502
- # extern mod sync;
503
- # fn main() {
504
- # use sync::DuplexStream;
505
- fn stringifier(channel: &DuplexStream<~str, uint>) {
506
- let mut value: uint;
507
- loop {
508
- value = channel.recv();
509
- channel.send(value.to_str());
510
- if value == 0 { break; }
511
- }
461
+ ~~~ {.ignore .linked-failure}
462
+ # use extra::comm::DuplexStream;
463
+ # use std::uint;
464
+ fn stringifier(channel: &DuplexStream<~str, uint>) {
465
+ let mut value: uint;
466
+ loop {
467
+ value = channel.recv();
468
+ channel.send(uint::to_str(value));
469
+ if value == 0 { break; }
512
470
}
513
- # }
471
+ }
514
472
~~~~
515
473
516
474
The implementation of `DuplexStream` supports both sending and
@@ -523,15 +481,15 @@ response itself is simply the stringified version of the received value,
523
481
524
482
Here is the code for the parent task:
525
483
526
- ~~~
527
- # extern mod sync;
484
+ ~~~{.ignore .linked-failure}
528
485
# use std::task::spawn;
529
- # use sync::DuplexStream;
486
+ # use std::uint;
487
+ # use extra::comm::DuplexStream;
530
488
# fn stringifier(channel: &DuplexStream<~str, uint>) {
531
489
# let mut value: uint;
532
490
# loop {
533
491
# value = channel.recv();
534
- # channel.send(value. to_str());
492
+ # channel.send(uint:: to_str(value ));
535
493
# if value == 0u { break; }
536
494
# }
537
495
# }
0 commit comments