@@ -39,26 +39,51 @@ 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 extra libraries, which are still under development
42
+ in the standard and sync 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
- * [ ` 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.
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.
55
69
56
70
[ `std::task` ] : std/task/index.html
57
71
[ `std::comm` ] : std/comm/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
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
62
87
63
88
# Basics
64
89
@@ -254,21 +279,25 @@ let result = ports.iter().fold(0, |accum, port| accum + port.recv() );
254
279
~~~
255
280
256
281
## Backgrounding computations: Futures
257
- With ` extra::future ` , rust has a mechanism for requesting a computation and getting the result
282
+ With ` sync::Future ` , rust has a mechanism for requesting a computation and getting the result
258
283
later.
259
284
260
285
The basic example below illustrates this.
261
286
262
287
~~~
288
+ # extern mod sync;
289
+
290
+ # fn main() {
263
291
# fn make_a_sandwich() {};
264
292
fn fib(n: u64) -> u64 {
265
293
// lengthy computation returning an uint
266
294
12586269025
267
295
}
268
296
269
- let mut delayed_fib = extra::future ::Future::spawn(proc() fib(50));
297
+ let mut delayed_fib = sync ::Future::spawn(proc() fib(50));
270
298
make_a_sandwich();
271
299
println!("fib(50) = {:?}", delayed_fib.get())
300
+ # }
272
301
~~~
273
302
274
303
The call to ` future::spawn ` returns immediately a ` future ` object regardless of how long it
@@ -281,6 +310,7 @@ Here is another example showing how futures allow you to background computations
281
310
be distributed on the available cores.
282
311
283
312
~~~
313
+ # extern mod sync;
284
314
# use std::vec;
285
315
fn partial_sum(start: uint) -> f64 {
286
316
let mut local_sum = 0f64;
@@ -291,7 +321,7 @@ fn partial_sum(start: uint) -> f64 {
291
321
}
292
322
293
323
fn main() {
294
- let mut futures = vec::from_fn(1000, |ind| extra::future ::Future::spawn( proc() { partial_sum(ind) }));
324
+ let mut futures = vec::from_fn(1000, |ind| sync ::Future::spawn( proc() { partial_sum(ind) }));
295
325
296
326
let mut final_res = 0f64;
297
327
for ft in futures.mut_iter() {
@@ -309,16 +339,17 @@ add up to a significant amount of wasted memory and would require copying the sa
309
339
necessary.
310
340
311
341
To tackle this issue, one can use an Atomically Reference Counted wrapper (` Arc ` ) as implemented in
312
- the ` extra ` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
342
+ the ` sync ` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc
313
343
acts as a reference to the shared data and only this reference is shared and cloned.
314
344
315
345
Here is a small example showing how to use Arcs. We wish to run concurrently several computations on
316
346
a single large vector of floats. Each task needs the full vector to perform its duty.
317
347
318
348
~~~
349
+ # extern mod sync;
319
350
# use std::vec;
320
351
# use std::rand;
321
- use extra::arc ::Arc;
352
+ use sync ::Arc;
322
353
323
354
fn pnorm(nums: &~[f64], p: uint) -> f64 {
324
355
nums.iter().fold(0.0, |a,b| a+(*b).powf(&(p as f64)) ).powf(&(1.0 / (p as f64)))
@@ -348,39 +379,48 @@ at the power given as argument and takes the inverse power of this value). The A
348
379
created by the line
349
380
350
381
~~~
351
- # use extra::arc::Arc;
382
+ # extern mod sync;
383
+ # use sync::Arc;
352
384
# use std::vec;
353
385
# use std::rand;
386
+ # fn main() {
354
387
# let numbers = vec::from_fn(1000000, |_| rand::random::<f64>());
355
388
let numbers_arc=Arc::new(numbers);
389
+ # }
356
390
~~~
357
391
358
392
and a clone of it is sent to each task
359
393
360
394
~~~
361
- # use extra::arc::Arc;
395
+ # extern mod sync;
396
+ # use sync::Arc;
362
397
# use std::vec;
363
398
# use std::rand;
399
+ # fn main() {
364
400
# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
365
401
# let numbers_arc = Arc::new(numbers);
366
402
# let (port, chan) = Chan::new();
367
403
chan.send(numbers_arc.clone());
404
+ # }
368
405
~~~
369
406
370
407
copying only the wrapper and not its contents.
371
408
372
409
Each task recovers the underlying data by
373
410
374
411
~~~
375
- # use extra::arc::Arc;
412
+ # extern mod sync;
413
+ # use sync::Arc;
376
414
# use std::vec;
377
415
# use std::rand;
416
+ # fn main() {
378
417
# let numbers=vec::from_fn(1000000, |_| rand::random::<f64>());
379
418
# let numbers_arc=Arc::new(numbers);
380
419
# let (port, chan) = Chan::new();
381
420
# chan.send(numbers_arc.clone());
382
421
# let local_arc : Arc<~[f64]> = port.recv();
383
422
let task_numbers = local_arc.get();
423
+ # }
384
424
~~~
385
425
386
426
and can use it as if it were local.
@@ -450,25 +490,27 @@ proceed).
450
490
451
491
A very common thing to do is to spawn a child task where the parent
452
492
and child both need to exchange messages with each other. The
453
- function ` extra ::comm::DuplexStream()` supports this pattern. We'll
493
+ function ` sync ::comm::DuplexStream()` supports this pattern. We'll
454
494
look briefly at how to use it.
455
495
456
496
To see how ` DuplexStream() ` works, we will create a child task
457
497
that repeatedly receives a ` uint ` message, converts it to a string, and sends
458
498
the string in response. The child terminates when it receives ` 0 ` .
459
499
Here is the function that implements the child task:
460
500
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; }
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
+ }
470
512
}
471
- }
513
+ # }
472
514
~~~~
473
515
474
516
The implementation of `DuplexStream` supports both sending and
@@ -481,15 +523,15 @@ response itself is simply the stringified version of the received value,
481
523
482
524
Here is the code for the parent task:
483
525
484
- ~~~{.ignore .linked-failure}
526
+ ~~~
527
+ # extern mod sync;
485
528
# use std::task::spawn;
486
- # use std::uint;
487
- # use extra::comm::DuplexStream;
529
+ # use sync::DuplexStream;
488
530
# fn stringifier(channel: &DuplexStream<~ str, uint>) {
489
531
# let mut value: uint;
490
532
# loop {
491
533
# value = channel.recv();
492
- # channel.send(uint:: to_str(value ));
534
+ # channel.send(value. to_str());
493
535
# if value == 0u { break; }
494
536
# }
495
537
# }
0 commit comments