#![allow(clippy::new_without_default, reason = "Not relevant for example")]
use std::thread;
mod counters {
use std::cell::Cell;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
#[linked::object]
pub(crate) struct EventCounter {
local_count: Cell<usize>,
global_count: Arc<AtomicUsize>,
}
impl EventCounter {
pub(crate) fn new() -> Self {
let global_count = Arc::new(AtomicUsize::new(0));
linked::new!(Self {
local_count: Cell::new(0),
global_count: Arc::clone(&global_count),
})
}
pub(crate) fn increment(&self) {
self.local_count
.set(self.local_count.get().saturating_add(1));
self.global_count.fetch_add(1, Ordering::Relaxed);
}
pub(crate) fn local_count(&self) -> usize {
self.local_count.get()
}
pub(crate) fn global_count(&self) -> usize {
self.global_count.load(Ordering::Relaxed)
}
}
}
use counters::EventCounter;
linked::thread_local_rc!(static RECORDS_PROCESSED: EventCounter = EventCounter::new());
fn main() {
const THREAD_COUNT: usize = 4;
const INCREMENT_ITERATIONS: usize = 1_000;
let mut threads = Vec::with_capacity(THREAD_COUNT);
for _ in 0..THREAD_COUNT {
threads.push(thread::spawn(move || {
RECORDS_PROCESSED.with(|x| x.increment());
let counter1 = RECORDS_PROCESSED.to_rc();
let counter2 = RECORDS_PROCESSED.to_rc();
for _ in 0..INCREMENT_ITERATIONS {
counter1.increment();
counter2.increment();
}
let counter3 = RECORDS_PROCESSED.to_rc();
println!(
"Thread completed work; thread local count: {}, global count: {}",
counter3.local_count(),
counter3.global_count()
);
}));
}
for thread in threads {
thread.join().unwrap();
}
let final_count = RECORDS_PROCESSED.to_rc().global_count();
println!("All threads completed work; final global count: {final_count}");
}