diff options
| author | JeremyLetang <letang.jeremy@gmail.com> | 2014-01-30 15:04:47 -0500 |
|---|---|---|
| committer | JeremyLetang <letang.jeremy@gmail.com> | 2014-02-05 11:56:04 -0500 |
| commit | dd21a51d294ad9843d61b7f2016957a279b0d64f (patch) | |
| tree | ac8a5dae28d90c9168b653d19cc879eab18c7b24 /src/doc | |
| parent | ed885e35fe91c12892bbf1254b4bc6259cc96eee (diff) | |
move concurrent stuff from libextra to libsync
Diffstat (limited to 'src/doc')
| -rw-r--r-- | src/doc/guide-tasks.md | 108 | ||||
| -rw-r--r-- | src/doc/index.md | 1 |
2 files changed, 76 insertions, 33 deletions
diff --git a/src/doc/guide-tasks.md b/src/doc/guide-tasks.md index c3bdbe3a3ee..387f481025d 100644 --- a/src/doc/guide-tasks.md +++ b/src/doc/guide-tasks.md @@ -39,7 +39,7 @@ data through the global _exchange heap_. While Rust's type system provides the building blocks needed for safe and efficient tasks, all of the task functionality itself is implemented -in the standard and extra libraries, which are still under development +in the standard and sync libraries, which are still under development and do not always present a consistent or complete interface. For your reference, these are the standard modules involved in Rust @@ -47,18 +47,43 @@ concurrency at this writing: * [`std::task`] - All code relating to tasks and task scheduling, * [`std::comm`] - The message passing interface, -* [`extra::comm`] - Additional messaging types based on `std::comm`, -* [`extra::sync`] - More exotic synchronization tools, including locks, -* [`extra::arc`] - The Arc (atomically reference counted) type, - for safely sharing immutable data, -* [`extra::future`] - A type representing values that may be computed concurrently and retrieved at a later time. +* [`sync::DuplexStream`] - An extension of `pipes::stream` that allows both sending and receiving, +* [`sync::SyncChan`] - An extension of `pipes::stream` that provides synchronous message sending, +* [`sync::SyncPort`] - An extension of `pipes::stream` that acknowledges each message received, +* [`sync::rendezvous`] - Creates a stream whose channel, upon sending a message, blocks until the + message is received. +* [`sync::Arc`] - The Arc (atomically reference counted) type, for safely sharing immutable data, +* [`sync::RWArc`] - A dual-mode Arc protected by a reader-writer lock, +* [`sync::MutexArc`] - An Arc with mutable data protected by a blocking mutex, +* [`sync::Semaphore`] - A counting, blocking, bounded-waiting semaphore, +* [`sync::Mutex`] - A blocking, bounded-waiting, mutual exclusion lock with an associated + FIFO condition variable, +* [`sync::RWLock`] - A blocking, no-starvation, reader-writer lock with an associated condvar, +* [`sync::Barrier`] - A barrier enables multiple tasks to synchronize the beginning + of some computation, +* [`sync::TaskPool`] - A task pool abstraction, +* [`sync::Future`] - A type encapsulating the result of a computation which may not be complete, +* [`sync::one`] - A "once initialization" primitive +* [`sync::mutex`] - A proper mutex implementation regardless of the "flavor of task" which is + acquiring the lock. [`std::task`]: std/task/index.html [`std::comm`]: std/comm/index.html -[`extra::comm`]: extra/comm/index.html -[`extra::sync`]: extra/sync/index.html -[`extra::arc`]: extra/arc/index.html -[`extra::future`]: extra/future/index.html +[`sync::DuplexStream`]: sync/struct.DuplexStream.html +[`sync::SyncChan`]: sync/struct.SyncChan.html +[`sync::SyncPort`]: sync/struct.SyncPort.html +[`sync::rendezvous`]: sync/fn.rendezvous.html +[`sync::Arc`]: sync/struct.Arc.html +[`sync::RWArc`]: sync/struct.RWArc.html +[`sync::MutexArc`]: sync/struct.MutexArc.html +[`sync::Semaphore`]: sync/struct.Semaphore.html +[`sync::Mutex`]: sync/struct.Mutex.html +[`sync::RWLock`]: sync/struct.RWLock.html +[`sync::Barrier`]: sync/struct.Barrier.html +[`sync::TaskPool`]: sync/struct.TaskPool.html +[`sync::Future`]: sync/struct.Future.html +[`sync::one`]: sync/one/index.html +[`sync::mutex`]: sync/mutex/index.html # Basics @@ -254,21 +279,25 @@ let result = ports.iter().fold(0, |accum, port| accum + port.recv() ); ~~~ ## Backgrounding computations: Futures -With `extra::future`, rust has a mechanism for requesting a computation and getting the result +With `sync::Future`, rust has a mechanism for requesting a computation and getting the result later. The basic example below illustrates this. ~~~ +# extern mod sync; + +# fn main() { # fn make_a_sandwich() {}; fn fib(n: u64) -> u64 { // lengthy computation returning an uint 12586269025 } -let mut delayed_fib = extra::future::Future::spawn(proc() fib(50)); +let mut delayed_fib = sync::Future::spawn(proc() fib(50)); make_a_sandwich(); println!("fib(50) = {:?}", delayed_fib.get()) +# } ~~~ 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 be distributed on the available cores. ~~~ +# extern mod sync; # use std::vec; fn partial_sum(start: uint) -> f64 { let mut local_sum = 0f64; @@ -291,7 +321,7 @@ fn partial_sum(start: uint) -> f64 { } fn main() { - let mut futures = vec::from_fn(1000, |ind| extra::future::Future::spawn( proc() { partial_sum(ind) })); + let mut futures = vec::from_fn(1000, |ind| sync::Future::spawn( proc() { partial_sum(ind) })); let mut final_res = 0f64; 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 necessary. To tackle this issue, one can use an Atomically Reference Counted wrapper (`Arc`) as implemented in -the `extra` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc +the `sync` library of Rust. With an Arc, the data will no longer be copied for each task. The Arc acts as a reference to the shared data and only this reference is shared and cloned. Here is a small example showing how to use Arcs. We wish to run concurrently several computations on a single large vector of floats. Each task needs the full vector to perform its duty. ~~~ +# extern mod sync; # use std::vec; # use std::rand; -use extra::arc::Arc; +use sync::Arc; fn pnorm(nums: &~[f64], p: uint) -> f64 { nums.iter().fold(0.0, |a,b| a+(*b).powf(&(p as f64)) ).powf(&(1.0 / (p as f64))) @@ -348,23 +379,29 @@ at the power given as argument and takes the inverse power of this value). The A created by the line ~~~ -# use extra::arc::Arc; +# extern mod sync; +# use sync::Arc; # use std::vec; # use std::rand; +# fn main() { # let numbers = vec::from_fn(1000000, |_| rand::random::<f64>()); let numbers_arc=Arc::new(numbers); +# } ~~~ and a clone of it is sent to each task ~~~ -# use extra::arc::Arc; +# extern mod sync; +# use sync::Arc; # use std::vec; # use std::rand; +# fn main() { # let numbers=vec::from_fn(1000000, |_| rand::random::<f64>()); # let numbers_arc = Arc::new(numbers); # let (port, chan) = Chan::new(); chan.send(numbers_arc.clone()); +# } ~~~ copying only the wrapper and not its contents. @@ -372,15 +409,18 @@ copying only the wrapper and not its contents. Each task recovers the underlying data by ~~~ -# use extra::arc::Arc; +# extern mod sync; +# use sync::Arc; # use std::vec; # use std::rand; +# fn main() { # let numbers=vec::from_fn(1000000, |_| rand::random::<f64>()); # let numbers_arc=Arc::new(numbers); # let (port, chan) = Chan::new(); # chan.send(numbers_arc.clone()); # let local_arc : Arc<~[f64]> = port.recv(); let task_numbers = local_arc.get(); +# } ~~~ and can use it as if it were local. @@ -450,7 +490,7 @@ proceed). 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 `extra::comm::DuplexStream()` supports this pattern. We'll +function `sync::comm::DuplexStream()` supports this pattern. We'll look briefly at how to use it. To see how `DuplexStream()` works, we will create a child task @@ -458,17 +498,19 @@ that repeatedly receives a `uint` message, converts it to a string, and sends the string in response. The child terminates when it receives `0`. Here is the function that implements the child task: -~~~{.ignore .linked-failure} -# use extra::comm::DuplexStream; -# use std::uint; -fn stringifier(channel: &DuplexStream<~str, uint>) { - let mut value: uint; - loop { - value = channel.recv(); - channel.send(uint::to_str(value)); - if value == 0 { break; } +~~~ +# extern mod sync; +# fn main() { +# use sync::DuplexStream; + fn stringifier(channel: &DuplexStream<~str, uint>) { + let mut value: uint; + loop { + value = channel.recv(); + channel.send(value.to_str()); + if value == 0 { break; } + } } -} +# } ~~~~ The implementation of `DuplexStream` supports both sending and @@ -481,15 +523,15 @@ response itself is simply the stringified version of the received value, Here is the code for the parent task: -~~~{.ignore .linked-failure} +~~~ +# extern mod sync; # use std::task::spawn; -# use std::uint; -# use extra::comm::DuplexStream; +# use sync::DuplexStream; # fn stringifier(channel: &DuplexStream<~str, uint>) { # let mut value: uint; # loop { # value = channel.recv(); -# channel.send(uint::to_str(value)); +# channel.send(value.to_str()); # if value == 0u { break; } # } # } diff --git a/src/doc/index.md b/src/doc/index.md index 9915d67bfca..5aa92c9fec4 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -43,6 +43,7 @@ li {list-style-type: none; } * [The `semver` version collation library](semver/index.html) * [The `term` terminal-handling library](term/index.html) * [The UUID library](uuid/index.html) +* [The `sync` library for concurrency-enabled mechanisms and primitives](sync/index.html) # Tooling |
