Crate voluntary_servitude[−][src]
Lockfree data-structures
Currently only implements a thread-safe appendable list with a lock-free iterator
Contains FFI implementation, see C examples in ./examples or in 'ffi' module
*Uses rust allocator by default, system allocator can be enable with the 'system-alloc' feature
cargo build --features "system-alloc"
To enable logging set the feature 'logs' (and the appropriate config in env var)
cargo build --features "logs"
Examples:
export RUST_LOG=voluntary_servitude=trace
export RUST_LOG=voluntary_servitude=debug
export RUST_LOG=voluntary_servitude=info
export RUST_LOG=voluntary_servitude=warn
To make the iterator thread safe set the feature 'iter-sync
cargo build --features "iter-sync"
Single thread
const ELEMENTS: usize = 10000; // Creates VSRead with 3 elements // vsread![] and VSRead::default() make an empty VSRead // vsread![1; 3] makes a VSRead with 3 elements equal to 1 let list = vsread![0, 1, 2]; // Current VSRead length // Be careful with data-races since the value, when used, may not be true anymore assert_eq!(list.len(), 3); // The 'iter' method makes a one-time lock-free iterator (VSReadIter) based on VSRead assert_eq!(list.iter().len(), 3); // You can get the current iteration index // (if iter.index() is equal to iter.len(), then the iteration ended - iter.next() is None) let mut iter = list.iter(); assert_eq!(iter.index(), 0); assert_eq!(iter.next(), Some(&0)); assert_eq!(iter.index(), 1); // Appends 9997 elements to it assert_eq!((3..ELEMENTS).map(|i| list.append(i)).count(), ELEMENTS - 3); // Iterates through all elements to ensure it's what we inserted let count = list.iter().enumerate().map(|(i, el)| assert_eq!(&i, el)).count(); assert_eq!(count, ELEMENTS); let iter2 = list.iter(); // List can also be cleared (but current iterators are not affected) list.clear(); assert_eq!(list.len(), 0); assert_eq!(list.iter().len(), 0); assert_eq!(list.iter().next(), None); assert_eq!(iter2.len(), ELEMENTS); let count = iter2.enumerate().map(|(i, el)| assert_eq!(&i, el)).count(); assert_eq!(count, ELEMENTS); println!("Single thread example ended without errors");
Multi producer, multi consumer
#[macro_use] extern crate voluntary_servitude; use std::{thread::spawn, sync::Arc}; const CONSUMERS: usize = 8; const PRODUCERS: usize = 4; const ELEMENTS: usize = 10000; let list = Arc::new(vsread![]); // or Arc::new(VSRead::default()); let mut handlers = vec![]; // Creates producer threads to insert 10k elements for _ in 0..PRODUCERS { let l = Arc::clone(&list); handlers.push(spawn(move || { let _ = (0..ELEMENTS).map(|i| l.append(i)).count(); })); } // Creates consumer threads to print number of elements until all of them are inserted for _ in 0..CONSUMERS { let consumer = Arc::clone(&list); handlers.push(spawn(move || { loop { let count = consumer.iter().count(); println!("{} elements", count); if count == PRODUCERS * ELEMENTS { break; } } })); } // Join threads for handler in handlers.into_iter() { handler.join().expect("Failed to join thread"); } println!("Multi thread example ended without errors");
Modules
ffi |
Voluntary Servitude Foreign Function Interface (FFI) |
Macros
vsread |
Creates new VSRead with specified elements as in the 'vec!' macro |
Structs
VSRead |
Appendable list that can become a lockfree iterator (one append blocks others - lock write only) |