global_counter

Crates.ioglobal_counter
lib.rsglobal_counter
version0.2.2
sourcesrc
created_at2020-01-13 12:36:37.182651
updated_at2021-03-18 10:24:22.828007
descriptionGlobal, thread-safe counters
homepage
repositoryhttps://github.com/LukiRe/global_counter
max_upload_size
id198066
size69,371
Lukas Riemer (lksriemer)

documentation

README

global_counter

Documentation

This crate implements global counters, generic and primitive, which build on thoroughly tested synchronization primitives, namely parking_lots Mutex (by default) and the stdlibs atomic types. Faster counters, which trade accuracy for performance, are also available. Refer to the documentation for details.

Usage

Add the following dependency to your Cargo.toml file:

[dependencies]
global_counter = "0.2.2"

Use the #[macro_use] annotation when importing, like this:

#[macro_use]
extern crate global_counter;

If you want to disable using parking_lot, and instead use the stdlibs Mutex, disable the default features:

[dependencies.global_counter]
version = "0.2.2"
default-features = false

Quickstart

Create a counter

use global_counter::generic::Counter;
use global_counter::primitive::exact::CounterI16;

// Generic
global_counter!(COUTER_NAME, CountedType, CountedType::default());

// If you feel funny, you can also create a generic global counter without a macro.
// Take a look at the implemtation of the macro, it's simply wrapping in a once_cell::sync::Lazy<...>.

// Primitive
static COUNTER_NAME : CounterI16 = CounterI16::new(0);

Count your counter up

COUNTER_NAME.inc();

Get the value of your counter

// Generic
let val_borrowed = COUNTER_NAME.get_borrowed();
// Or
let val = COUNTER_NAME.get_cloned();

// Primitive
let val = COUNTER_NAME.get();

Example - Primitive counter used for indexing into vec from multiple threads

#[macro_use]
extern crate global_counter;

use global_counter::primitive::exact::CounterUsize;
use std::sync::{Arc, Mutex};

fn main() {
    // This is a primitive counter. Implemented using atomics, more efficient than its generic equivalent.
    // Available for primitive integer types.
    static COUNTER: CounterUsize = CounterUsize::new(0);

    // We want to copy the 'from' arr to the 'to' arr. From multiple threads.
    // Please don't do this in actual code.
    let from = Arc::new(Mutex::new(vec![1, 5, 22, 10000, 43, -4, 39, 1, 2]));
    let to = Arc::new(Mutex::new(vec![0, 0, 0, 0, 0, 0, 0, 0, 0]));

    // 3 elements each in two other threads + 3 elements in this thread.
    // After joining those two threads, all elements will have been copied.
    let to_arc = to.clone();
    let from_arc = from.clone();
    let t1 = std::thread::spawn(move || {
        // '.inc()' increments the counter, returning the previous value.
        let indices = [COUNTER.inc(), COUNTER.inc(), COUNTER.inc()];
        for &i in indices.iter() {
            to_arc.lock().unwrap()[i] = from_arc.lock().unwrap()[i];
        }
    });

    let to_arc = to.clone();
    let from_arc = from.clone();
    let t2 = std::thread::spawn(move || {
        let indices = [COUNTER.inc(), COUNTER.inc(), COUNTER.inc()];
        for &i in indices.iter() {
            to_arc.lock().unwrap()[i] = from_arc.lock().unwrap()[i];
        }
    });

    let indices = [COUNTER.inc(), COUNTER.inc(), COUNTER.inc()];
    for &i in indices.iter() {
        to.lock().unwrap()[i] = from.lock().unwrap()[i];
    }

    t1.join().unwrap();
    t2.join().unwrap();

    assert_eq!(**to.lock().unwrap(), **from.lock().unwrap());
}

Example - No cloning of counted struct

#[macro_use]
extern crate global_counter;

use global_counter::generic::{Counter, Inc};
use std::collections::LinkedList;
use std::iter::FromIterator;

// Note how this (supposedly) doesn't implement `Clone`.
#[derive(Debug, PartialEq, Eq)]
struct CardinalityCountedList(LinkedList<()>);

// Incrementing to us means just inserting another element.
impl Inc for CardinalityCountedList {
    fn inc(&mut self) {
        self.0.push_back(());
    }
}

// Some helper methods.
impl CardinalityCountedList {
    pub fn with_cardinality(card: usize) -> Self {
        CardinalityCountedList(LinkedList::from_iter(std::iter::repeat(()).take(card)))
    }

    pub fn card(&self) -> usize {
        self.0.len()
    }
}

// We create a new global, thread-safe Counter.
// Could also do this in the main fn or wherever.
global_counter!(
    COUNTER, // Name
    CardinalityCountedList, // Type
    CardinalityCountedList::with_cardinality(0) // Initial value
);

fn main() {
    // Note how we use a borrow, but never clone this LinkedList.
    // Of course, a cloning, convenient API is also available.
    assert_eq!((*COUNTER.get_borrowed()).card(), 0);

    let t1 = std::thread::spawn(move || {
        for _ in 0..(1 << 20) {
            COUNTER.inc();
        }
    });
    let t2 = std::thread::spawn(move || {
        for _ in 0..(1 << 20) {
            COUNTER.inc();
        }
    });

    t1.join().unwrap();

    let card = (*COUNTER.get_borrowed()).card();

    // t1 finished, t2 maybe did something.
    assert!((1 << 20) <= card && card <= (2 << 20));

    t2.join().unwrap();

    // Both threads finished, the counter guarantees `Inc` was executed 2 << 20 times.
    assert_eq!((*COUNTER.get_borrowed()).card(), 2 << 20);
}

Changelog

This library is still being developed. A detailed changelog will be introduced, once a relatively stable state is reached. Treat every version bump as a breaking change.

Minimum Rust version

Starting with version 0.2.2, this crate requires Rust version 1.46 or up to be compiled.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Commit count: 114

cargo fmt