#![allow(clippy::new_without_default, reason = "Not relevant for example")]
use std::thread;
mod counters {
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
pub(crate) trait CountResult {
fn local_count(&self) -> usize;
fn global_count(&self) -> usize;
}
#[linked::object]
pub(crate) struct EventCounter {
local_count: 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: 0,
global_count: Arc::clone(&global_count),
})
}
pub(crate) fn increment(&mut self) {
self.local_count = self.local_count.saturating_add(1);
self.global_count.fetch_add(1, Ordering::Relaxed);
}
}
impl CountResult for EventCounter {
fn local_count(&self) -> usize {
self.local_count
}
fn global_count(&self) -> usize {
self.global_count.load(Ordering::Relaxed)
}
}
}
use counters::{CountResult, EventCounter};
linked::instances!(static RECORDS_PROCESSED: EventCounter = EventCounter::new());
#[expect(clippy::needless_pass_by_value, reason = "adding realism to example")]
fn finalize_counter_processing(result: Box<dyn CountResult>) {
println!(
"Counter finished counting: local count: {}, global count: {}",
result.local_count(),
result.global_count()
);
}
fn main() {
const THREAD_COUNT: usize = 4;
const RECORDS_PER_THREAD: usize = 1_000;
let mut threads = Vec::with_capacity(THREAD_COUNT);
for _ in 0..THREAD_COUNT {
threads.push(thread::spawn(move || {
let mut counter = RECORDS_PROCESSED.get();
for _ in 0..RECORDS_PER_THREAD {
counter.increment();
}
let boxed_count_result = Box::new(counter);
finalize_counter_processing(boxed_count_result);
}));
}
for thread in threads {
thread.join().unwrap();
}
let final_count = RECORDS_PROCESSED.get().global_count();
println!("All threads completed work; final global count: {final_count}");
}