67 lines
1.7 KiB
Rust
67 lines
1.7 KiB
Rust
|
use std::sync::atomic::AtomicUsize;
|
||
|
use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed};
|
||
|
use std::sync::Arc;
|
||
|
use std::thread;
|
||
|
use std::time::{Duration, Instant};
|
||
|
|
||
|
use crossbeam_epoch::{self as epoch, Atomic, Collector, LocalHandle, Owned, Shared};
|
||
|
use rand::Rng;
|
||
|
|
||
|
fn worker(a: Arc<Atomic<AtomicUsize>>, handle: LocalHandle) -> usize {
|
||
|
let mut rng = rand::thread_rng();
|
||
|
let mut sum = 0;
|
||
|
|
||
|
if rng.gen() {
|
||
|
thread::sleep(Duration::from_millis(1));
|
||
|
}
|
||
|
let timeout = Duration::from_millis(rng.gen_range(0..10));
|
||
|
let now = Instant::now();
|
||
|
|
||
|
while now.elapsed() < timeout {
|
||
|
for _ in 0..100 {
|
||
|
let guard = &handle.pin();
|
||
|
guard.flush();
|
||
|
|
||
|
let val = if rng.gen() {
|
||
|
let p = a.swap(Owned::new(AtomicUsize::new(sum)), AcqRel, guard);
|
||
|
unsafe {
|
||
|
guard.defer_destroy(p);
|
||
|
guard.flush();
|
||
|
p.deref().load(Relaxed)
|
||
|
}
|
||
|
} else {
|
||
|
let p = a.load(Acquire, guard);
|
||
|
unsafe { p.deref().fetch_add(sum, Relaxed) }
|
||
|
};
|
||
|
|
||
|
sum = sum.wrapping_add(val);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
sum
|
||
|
}
|
||
|
|
||
|
fn main() {
|
||
|
for _ in 0..100 {
|
||
|
let collector = Collector::new();
|
||
|
let a = Arc::new(Atomic::new(AtomicUsize::new(777)));
|
||
|
|
||
|
let threads = (0..16)
|
||
|
.map(|_| {
|
||
|
let a = a.clone();
|
||
|
let c = collector.clone();
|
||
|
thread::spawn(move || worker(a, c.register()))
|
||
|
})
|
||
|
.collect::<Vec<_>>();
|
||
|
|
||
|
for t in threads {
|
||
|
t.join().unwrap();
|
||
|
}
|
||
|
|
||
|
unsafe {
|
||
|
a.swap(Shared::null(), AcqRel, epoch::unprotected())
|
||
|
.into_owned();
|
||
|
}
|
||
|
}
|
||
|
}
|