#atomic #interval #timer #lock-free #time

atomic-interval

A tiny implementation of an atomic timer

5 releases

0.1.4 Feb 15, 2024
0.1.3 Nov 22, 2021
0.1.2 Nov 21, 2021
0.1.1 Nov 17, 2021
0.1.0 Nov 15, 2021

#191 in Concurrency

Download history 33/week @ 2023-12-16 2/week @ 2023-12-30 3/week @ 2024-01-06 16/week @ 2024-01-13 130/week @ 2024-02-10 141/week @ 2024-02-17 76/week @ 2024-02-24 24/week @ 2024-03-02 26/week @ 2024-03-09 52/week @ 2024-03-16 10/week @ 2024-03-23 40/week @ 2024-03-30

129 downloads per month

MIT/Apache

12KB
134 lines

atomic-interval

crates.io docs.rs Build

A very tiny library implementing a lock-free atomic timer.

Documentation

Docs.rs

Example

In the following example, we have a concurrent scenario where multiple threads want to push a data sample towards a single and common entity (e.g., a static function, a multi-referenced object, and so on).

The entity wants to provide a "limiter" mechanism, where it actually processes a sample with a limited frequency.

Therefore, even if concurrently threads push with a higher frequency, only one sample (coming from one thread) for each period can be actually processed (i.e., printed).

AtomicInterval can be used without an additional sync mechanism, as it can already be safely shared across threads.

use atomic_interval::AtomicIntervalLight;
use once_cell::sync::OnceCell;
use std::thread;
use std::time::Duration;

const MAX_PERIOD_SAMPLING: Duration = Duration::from_secs(1);

fn push_sample(id_thread: usize, value: u8) {
    // Note AtomicInterval can be used without additional
    // sync wrapper (e.g., a `Mutex`) as it is atomic.
    static LIMITER: OnceCell<AtomicIntervalLight> = OnceCell::new();

    let limiter_init = || AtomicIntervalLight::new(MAX_PERIOD_SAMPLING);

    // Only one threads can push a sample for each PERIOD.
    // We limit the samples acquisition with a interval.
    if LIMITER.get_or_init(limiter_init).is_ticked() {
        println!("Thread '{}' pushed sample: '{}'", id_thread, value);
    }
}

fn main() {
    let num_threads = num_cpus::get();

    (0..num_threads)
        .map(|id_thread| {
            thread::spawn(move || loop {
                let sample = rand::random();

                // Multiple threads concurrently try to push a sample.
                push_sample(id_thread, sample);

                thread::sleep(Duration::from_millis(1));
            })
        })
        .collect::<Vec<_>>()
        .into_iter()
        .for_each(|join_handle| join_handle.join().unwrap());
}

Dependencies

~0.8–2.4MB
~42K SLoC