1use std::sync::atomic::AtomicUsize;
2use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed};
3use std::sync::Arc;
4use std::thread;
5use std::time::{Duration, Instant};
6
7use crossbeam_epoch::{self as epoch, Atomic, Collector, LocalHandle, Owned, Shared};
8use rand::Rng;
9
10fn worker(a: Arc<Atomic<AtomicUsize>>, handle: LocalHandle) -> usize {
11 let mut rng = rand::thread_rng();
12 let mut sum = 0;
13
14 if rng.gen() {
15 thread::sleep(Duration::from_millis(1));
16 }
17 let timeout = Duration::from_millis(rng.gen_range(0..10));
18 let now = Instant::now();
19
20 while now.elapsed() < timeout {
21 for _ in 0..100 {
22 let guard = &handle.pin();
23 guard.flush();
24
25 let val = if rng.gen() {
26 let p = a.swap(Owned::new(AtomicUsize::new(sum)), AcqRel, guard);
27 unsafe {
28 guard.defer_destroy(p);
29 guard.flush();
30 p.deref().load(Relaxed)
31 }
32 } else {
33 let p = a.load(Acquire, guard);
34 unsafe { p.deref().fetch_add(sum, Relaxed) }
35 };
36
37 sum = sum.wrapping_add(val);
38 }
39 }
40
41 sum
42}
43
44fn main() {
45 for _ in 0..100 {
46 let collector = Collector::new();
47 let a = Arc::new(Atomic::new(AtomicUsize::new(777)));
48
49 let threads = (0..16)
50 .map(|_| {
51 let a = a.clone();
52 let c = collector.clone();
53 thread::spawn(move || worker(a, c.register()))
54 })
55 .collect::<Vec<_>>();
56
57 for t in threads {
58 t.join().unwrap();
59 }
60
61 unsafe {
62 a.swap(Shared::null(), AcqRel, epoch::unprotected())
63 .into_owned();
64 }
65 }
66}
67