1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183
//! [](https://circleci.com/gh/wbcchsyn/spin-sync-rs) //! [](https://travis-ci.org/wbcchsyn/spin-sync-rs) //! //! spin-sync is a module providing synchronization primitives using spinlock. ([Wikipedia Spinlock](https://en.wikipedia.org/wiki/Spinlock)) //! //! The main features are as follows. //! //! * Declaring public structs `Mutex` and `RwLock` , whose interfaces are resembles those of `std::sync` . //! * Ensuring safety as much as `std::sync` , including poisoning strategy and marker traits. //! //! ## How to use //! //! 1. Add the following line in dependencies section in your Cargo.toml. //! //! ```Cargo.toml //! spin-sync = "0.1.2" //! ``` //! //! 1. Build, test and run your project. //! //! ```shell //! cargo build //! cargo test //! cargo run //! ``` //! //! ## Examples //! //! ### Mutex<T> //! //! `Mutex::lock()` acquires the exclusive lock and returns an RAII guard object. The lock will be released when the guard is dropped (falls out of scope.) //! //! The data protected by the mutex can be accessed through this guard via its `Defer` and `DeferMut` implementations. //! //! ``` //! extern crate spin_sync; //! //! use spin_sync::Mutex; //! use std::sync::Arc; //! use std::thread; //! //! /// Create a variable protected by a Mutex, increment it in worker threads, //! /// and check the variable was updated rightly. //! fn main() { //! const WORKER_NUM: usize = 10; //! let mut handles = Vec::with_capacity(WORKER_NUM); //! //! // Decrare a variable protected by Mutex. //! // It is wrapped in std::Arc to share this mutex itself among threads. //! let mutex = Arc::new(Mutex::new(0)); //! //! // Create worker threads to inclement the value by 1. //! for _ in 0..WORKER_NUM { //! let mutex = mutex.clone(); //! //! let handle = thread::spawn(move || { //! let mut num = mutex.lock().unwrap(); //! *num += 1; //! }); //! //! handles.push(handle); //! } //! //! // Wait for the all worker threads are finished. //! for handle in handles { //! handle.join().unwrap(); //! } //! //! // Make sure the value is incremented by the worker count. //! let num = mutex.lock().unwrap(); //! assert_eq!(WORKER_NUM, *num); //! } //! ``` //! //! ### RwLock<T> //! //! `RwLock` resembles `Mutex` except for it distinguishes readers and writers. //! //! `RwLock::write()` behaves like `Mutex::lock()` . //! It acquires the exclusive write lock and returns an RAII guard object. The lock will be released when the guard is dropped (falls out of scope.) //! This guard allows read/write access (exclusive access) to the underlying data via its `Defer` and `DeferMut` implementations. //! //! `RwLock::read()` behaves like `RwLock::write()` except for it acquires a shared read lock //! (i.e. this method allows any number of readers to hold a shared read lock at the same time as long as no writer is not holding the exclusive write lock.) //! This guard allows read-only access (shared access) to the underlying data via its `Defer` implementation. //! //! ``` //! extern crate spin_sync; //! //! use spin_sync::RwLock; //! use std::sync::Arc; //! use std::thread; //! //! /// Create a variable protected by a RwLock, increment it by 2 in worker threads, //! /// and check the variable was updated rightly. //! fn main() { //! const WORKER_NUM: usize = 10; //! let mut handles = Vec::with_capacity(WORKER_NUM); //! //! // Decrare a variable protected by RwLock. //! // It is wrapped in std::Arc to share this instance itself among threads. //! let rwlock = Arc::new(RwLock::new(0)); //! //! // Create worker threads to inclement the value by 2. //! for _ in 0..WORKER_NUM { //! let c_rwlock = rwlock.clone(); //! //! let handle = thread::spawn(move || { //! let mut num = c_rwlock.write().unwrap(); //! *num += 2; //! }); //! //! handles.push(handle); //! } //! //! // Make sure the value is always multipile of 2 even if some worker threads //! // are working (it is incremented by 2.) //! // //! // Enclosing the lock with `{}` to drop it before waiting for the worker //! // threads; otherwise, deadlocks could be occurred. //! { //! let num = rwlock.read().unwrap(); //! assert_eq!(0, *num % 2); //! } //! //! // Wait for the all worker threads are finished. //! for handle in handles { //! handle.join().unwrap(); //! } //! //! // Make sure the value is incremented by 2 times the worker count. //! let num = rwlock.read().unwrap(); //! assert_eq!(2 * WORKER_NUM, *num); //! } //! ``` //! //! ### Once //! //! `Once.call_once` executes the given closure at least once and only once. It also //! guaratees that the closure has finished when it returned; i.e. any memory write can be //! reliably observed by the other threads at that point. //! //! `Once` acquires lock internally, so we can access to static mut data safely. //! //! ``` //! extern crate spin_sync; //! //! use spin_sync::Once; //! //! static mut CACHE: Option<usize> = None; //! static INIT: Once = Once::new(); //! //! /// Acquire the cached value. //! /// If the cache is not initialized, this function substitutes //! /// the argument val for the cache. //! /// //! /// This function is thread safe. //! fn get_cache(val: usize) -> usize { //! unsafe { //! INIT.call_once(|| CACHE = Some(val)); //! CACHE.unwrap() //! } //! } //! //! fn main() { //! // Initialize cache 5. //! assert_eq!(5, get_cache(5)); //! //! // Just return cached value. //! assert_eq!(5, get_cache(10)); //! } //! ``` mod misc; mod mutex; mod once; mod result; mod rwlock; pub use crate::mutex::{Mutex, MutexGuard}; pub use crate::once::{Once, OnceState}; pub use crate::result::{LockResult, PoisonError, TryLockError, TryLockResult}; pub use crate::rwlock::{RwLock, RwLockReadGuard, RwLockWriteGuard};