Card 1 / 5
Count across threads with no Mutex at all: threads threads each bump one shared atomic counter per times. Return the final value.
threads |
per |
result |
|---|---|---|
10 |
1000 |
10000 |
1 |
0 |
0 |
0 |
100 |
0 |
AtomicUsize::new(0) inside an Arc is the entire shared state — Arc::clone(&counter) copies the pointer into each thread. c.fetch_add(1, Ordering::Relaxed) adds one and returns the previous value as a single indivisible operation: no lock, no guard, nothing to drop.
The Ordering argument chooses how strictly this operation may be reordered against other variables. Relaxed promises only that the counter itself never loses an increment, which is all a standalone tally needs; SeqCst additionally places the operation in one global order that every thread agrees on. Read the total out at the end with counter.load(...).
/// Spawn `threads` threads that each call fetch_add(1) `per` times on a shared
/// atomic counter (no Mutex). Return the final value.
fn atomic_counter(threads: usize, per: usize) -> usize {
let counter = Arc::new(AtomicUsize::new(0));
let handles: Vec<_> = (0..threads)
.map(|_| {
let c = Arc::clone(&counter);
thread::spawn(move || {
for _ in 0..per {
c.fetch_add(1, Ordering::Relaxed);
}
})
})
.collect();
for h in handles {
h.join().unwrap();
}
counter.load(Ordering::SeqCst)
}Card 2 / 5
Raise cell to the maximum of its current value and candidate with a compare_exchange retry loop, returning the value stored afterwards.