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)