├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── examples └── threads.rs └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: rust 3 | matrix: 4 | fast_finish: true 5 | include: 6 | - rust: nightly 7 | - rust: beta 8 | - rust: stable 9 | script: 10 | - cargo build 11 | - cargo test 12 | - cargo bench 13 | cache: 14 | apt: true 15 | directories: 16 | - target/debug/deps 17 | - target/debug/build 18 | addons: 19 | apt: 20 | packages: 21 | - libcurl4-openssl-dev 22 | - libelf-dev 23 | - libdw-dev 24 | after_success: |- 25 | [ $TRAVIS_RUST_VERSION = stable ] && 26 | [ $TRAVIS_BRANCH = master ] && 27 | [ $TRAVIS_PULL_REQUEST = false ] && 28 | [ $TRAVIS_RUST_VERSION = stable ] && 29 | cargo doc --no-deps && 30 | echo "" > target/doc/index.html && 31 | pip install --user ghp-import && 32 | /home/travis/.local/bin/ghp-import -n target/doc && 33 | git push -fq https://${GH_TOKEN}@github.com/${TRAVIS_REPO_SLUG}.git gh-pages 34 | env: 35 | global: 36 | secure: XQ0j/e+pTb78AFLXfP6z7+RGxK9xWlpCexhU7rog9k/SbVsIEtVAxD1QoqanDbR5P3uJ8IMcq1mbZnoCer8M68dTJjREoSwwBknLok+LIAYYSVrtiNKfi+jIAT293KwjKL3DFnAo9R6a33waCRRvZy8nXc14gpEWJqLIQXB9xI18lAL+/uCf8GkuE6xGC8MGUSTW23bYbcMr7kkI/6+6OBr6S4q37n/iNdccJLdd3H9GB0Mne4I016SmQ14KF3eT7xCmrt8TAO27PXwnet+rviAOPDBdWAWWoBGJ18HHiMaGHScNx0WtMC5hDH0YMmg62v/r+wNNv2Oil6hW1BBY7lEoCpW0Qbmy2TJXaWNPMHcjRMKw2rNx4mu8in174XmKmWKHc6PXp1GWOnDIG0XStv3dtLCOYFflSEeU869nHCyVrbNf0OK1JKpuWKUyFZjH+lCI0dwyTZJ7N7g/N4yduMiyDIW9RR9zZJt8+ToR/1vq+IPxq81u7Vmpgtsz940jt19gTObJuJQ3zBsrOpQ87bnU1YGeMevjJHCqnDtLoEBPxpsrwhJ0DFIsWCFEhdR8EcKlLf76nCTCgW9GqWpzkQPOrZOQqTu8i8eyuC0WahcZ5pywUGVtMb4T9jeGZa7Sf9zpnlzlCgBy7p/ca6+H5z/WLinTEB3vzRFJP3sPgT8= 37 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.1.1 2 | 3 | * notify all waiters instead of one [issue#2](https://github.com/softprops/waitout/issues/2) 4 | * imporve efficiency of waiter notification [issue#3](https://github.com/softprops/waitout/issues/3) 5 | 6 | # 0.1.0 7 | 8 | Initial release 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "waitout" 3 | version = "0.1.1" 4 | authors = ["softprops "] 5 | description = "Awaits the completion of multiple async tasks" 6 | documentation = "http://softprops.github.io/waitout" 7 | homepage = "https://github.com/softprops/waitout" 8 | repository = "https://github.com/softprops/waitout" 9 | keywords = ["waitgroup", "countdownlatch", "async", "thread"] 10 | license = "MIT" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Doug Tangren 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # waitout 2 | 3 | [![Build Status](https://travis-ci.org/softprops/waitout.svg?branch=master)](https://travis-ci.org/softprops/waitout) 4 | 5 | Waitout provides a simple interface for tracking and awaiting the completion of multiple 6 | asynchounous tasks. 7 | 8 | ## api docs 9 | 10 | Find them [here](https://softprops.github.io/waitout). 11 | 12 | ## install 13 | 14 | Add the following to you're `Cargo.toml` file 15 | 16 | ```toml 17 | [dependencies] 18 | waitout = "0.1" 19 | ``` 20 | 21 | ## usage 22 | 23 | It's sometimes useful to fan out independant tasks asynchronously for efficient completion of 24 | an aggregate task. Asynchronous tasks may sometimes be staged in various scopes making it difficult 25 | to monitor the current state of their completion. Some languages have std library interfaces like [CountDownLatches](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html) and [WaitGroups](https://golang.org/pkg/sync/#WaitGroup) to help solve this problem. Absent of a similar interface in rust, the motivation for waitout was born. 26 | 27 | Waitout is a simple wrapper around of few rust synchronisation primitives that make staged task completion more straight forward. 28 | The idea is simple, keep reference create a shared counter that increments for every task you wish to wait on. 29 | When a task completes decrement that counter. When the counter reaches 0, the current thread may proceed. 30 | 31 | ```rust 32 | extern crate waitout; 33 | 34 | use std::sync::Arc; 35 | use std::thread; 36 | use waitout::WaitGroup; 37 | 38 | fn main() { 39 | let wg = Arc::new( 40 | WaitGroup::new(0) 41 | ); 42 | for _ in 0..100 { 43 | wg.add(1); 44 | let wg2 = wg.clone(); 45 | thread::spawn(move|| { 46 | thread::sleep_ms(2000); 47 | wg2.done(); 48 | }); 49 | } 50 | wg.wait(); 51 | println!("all set") 52 | } 53 | ``` 54 | 55 | Doug Tangren (softprops) 2015 56 | -------------------------------------------------------------------------------- /examples/threads.rs: -------------------------------------------------------------------------------- 1 | extern crate waitout; 2 | 3 | use waitout::WaitGroup; 4 | use std::sync::Arc; 5 | use std::thread; 6 | 7 | fn main() { 8 | let wg = Arc::new(WaitGroup::new(0)); 9 | for _ in 0..100 { 10 | wg.add(1); 11 | let wg2 = wg.clone(); 12 | thread::spawn(move || { 13 | thread::sleep_ms(2000); 14 | wg2.done(); 15 | }); 16 | } 17 | wg.wait(); 18 | println!("done") 19 | } 20 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! waitgroup provides an interface for awaiting the completion of multiple asynchronous tasks 2 | 3 | use std::sync::{Condvar, Mutex}; 4 | 5 | /// A waitgroup waits for a collection of tasks to complete. 6 | /// It keeps track of tasks via shared counter 7 | pub struct WaitGroup { 8 | cvar: Condvar, 9 | count: Mutex, 10 | } 11 | 12 | impl Default for WaitGroup { 13 | fn default() -> WaitGroup { 14 | WaitGroup::new(0) 15 | } 16 | } 17 | 18 | impl WaitGroup { 19 | /// creates a new wait group instance 20 | pub fn new(n: usize) -> WaitGroup { 21 | WaitGroup { 22 | cvar: Condvar::new(), 23 | count: Mutex::new(n), 24 | } 25 | } 26 | 27 | /// adds `delta` to internal counter 28 | pub fn add(&self, delta: usize) { 29 | let mut count = self.count.lock().unwrap(); 30 | *count += delta; 31 | self.notify_if_empty(*count) 32 | } 33 | 34 | /// subtracts 1 from internal counter 35 | pub fn done(&self) { 36 | let mut count = self.count.lock().unwrap(); 37 | *count -= 1; 38 | self.notify_if_empty(*count) 39 | } 40 | 41 | fn notify_if_empty(&self, count: usize) { 42 | if count <= 0 { 43 | self.cvar.notify_all(); 44 | } 45 | } 46 | 47 | /// blocks the current thread until wait group is complete 48 | pub fn wait(&self) { 49 | let mut count = self.count.lock().unwrap(); 50 | while *count > 0 { 51 | count = self.cvar.wait(count).unwrap(); 52 | } 53 | } 54 | } 55 | 56 | #[test] 57 | fn it_works() {} 58 | --------------------------------------------------------------------------------