1 use std::sync::atomic::AtomicUsize;
2 use std::sync::atomic::Ordering::{AcqRel, Acquire, Relaxed};
3 use std::sync::Arc;
4 use std::thread;
5 use std::time::{Duration, Instant};
6 
7 use crossbeam_epoch::{self as epoch, Atomic, Collector, LocalHandle, Owned, Shared};
8 use rand::Rng;
9 
worker(a: Arc<Atomic<AtomicUsize>>, handle: LocalHandle) -> usize10 fn 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 
main()44 fn 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