docs.rs failed to build voluntary-servitude-1.0.4
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build:
voluntary-servitude-4.0.8
Voluntary Servitude
-
Currently implements a thread-safe appendable list with a lock-free iterator
-
FFI implementation available, C examples are in ./examples folder
cd examples && make test
(runs rust and C examples) -
Last release is in ./dist
-
Uses system allocator by default, jemmaloc can be enabled with the 'jemmaloc' feature
-
Logging is available behind the 'logs' feature and RUST_LOG env var
Examples
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;
fn main() {
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");
}
Single thread C example (FFI)
#include<assert.h>
#include<stdio.h>
#include "include/voluntary_servitude.h"
int main(int argc, char **argv) {
// Rust allocates memory through malloc
vsread_t * vsread = vsread_new();
// Current vsread_t length
// Be careful with data-races since the value, when used, may not be true anymore
assert(vsread_len(vsread) == 0);
const unsigned int data[2] = {12, 25};
// Inserts void pointer to data to end of vsread_t
vsread_append(vsread, (void *) &data[0]);
vsread_append(vsread, (void *) &data[1]);
// Creates a one-time lock-free iterator based on vsread_t
vsread_iter_t * iter = vsread_iter(vsread);
// Index changes as you iter through vsread_iter_t
assert(vsread_iter_index(iter) == 0);
// Clearing vsread_t, doesn't change existing iterators
vsread_clear(vsread);
assert(vsread_len(vsread) == 0);
assert(vsread_iter_len(iter) == 2);
assert(*(unsigned int *) vsread_iter_next(iter) == 12);
assert(vsread_iter_index(iter) == 1);
assert(*(unsigned int *) vsread_iter_next(iter) == 25);
assert(vsread_iter_index(iter) == 2);
assert(vsread_iter_next(iter) == NULL);
assert(vsread_iter_index(iter) == 2);
assert(vsread_iter_len(iter) == 2);
// Never forget to free vsread_iter_t
assert(vsread_iter_destroy(iter) == 0);
// Create updated vsread_iter_t
vsread_iter_t * iter2 = vsread_iter(vsread);
// Never forget to free vsread_t
assert(vsread_destroy(vsread) == 0);
// vsread_iter_t keeps existing after the original vsread_t is freed
assert(vsread_iter_len(iter2) == 0);
assert(vsread_iter_next(iter2) == NULL);
assert(vsread_iter_index(iter2) == 0);
assert(vsread_iter_destroy(iter2) == 0);
printf("Single thread example ended without errors\n");
(void) argc;
(void) argv;
return 0;
}
Multi thread C example (FFI)
#include<pthread.h>
#include<assert.h>
#include<stdio.h>
#include "../include/voluntary_servitude.h"
const unsigned int num_producers = 4;
const unsigned int num_consumers = 8;
const unsigned int num_producer_values = 1000;
const unsigned int data[3] = {12, 25, 89};
const size_t last_index = sizeof(data) / sizeof(data[0]) - 1;
void * producer();
void * consumer();
int main(int argc, char** argv) {
// Rust allocates memory through malloc
vsread_t * const vsread = vsread_new();
unsigned int current_thread = 0;
pthread_attr_t attr;
pthread_t consumers[num_consumers],
producers[num_producers];
if (pthread_attr_init(&attr) != 0) {
fprintf(stderr, "Failed to initialize pthread arguments.\n");
exit(-1);
}
// Creates producer threads
for (current_thread = 0; current_thread < num_producers; ++current_thread) {
if (pthread_create(&producers[current_thread], &attr, &producer, (void *) vsread) != 0) {
fprintf(stderr, "Failed to create producer thread %d.\n", current_thread);
exit(-2);
}
}
// Creates consumers threads
for (current_thread = 0; current_thread < num_consumers; ++current_thread) {
if (pthread_create(&consumers[current_thread], &attr, &consumer, (void *) vsread) != 0) {
fprintf(stderr, "Failed to create consumer thread %d.\n", current_thread);
exit(-3);
}
}
// Join all threads, ensuring vsread_t* is not used anymore
for (current_thread = 0; current_thread < num_producers; ++current_thread) {
pthread_join(producers[current_thread], NULL);
}
for (current_thread = 0; current_thread < num_consumers; ++current_thread) {
pthread_join(consumers[current_thread], NULL);
}
// Never forget to free the memory allocated through rust
assert(vsread_destroy(vsread) == 0);
printf("Multi thread example ended without errors\n");
(void) argc;
(void) argv;
return 0;
}
void * producer(void * const vsread){
unsigned int index;
for (index = 0; index < num_producer_values; ++index) {
assert(vsread_append(vsread, (void *) &data[index % last_index]) == 0);
}
return NULL;
}
void * consumer(void * const vsread) {
const unsigned int total_values = num_producers * num_producer_values;
unsigned int values;
while (values < total_values) {
unsigned int sum = (values = 0);
vsread_iter_t * const iter = vsread_iter(vsread);
const void * value;
while ((value = vsread_iter_next(iter)) != NULL) {
++values;
sum += *(unsigned int *) value;
}
printf("Consumer counts %d elements summing %d.\n", values, sum);
assert(vsread_iter_destroy(iter) == 0);
}
return NULL;
}