#![deny(warnings, rust_2018_idioms)] use loom::sync::atomic::AtomicUsize; use loom::thread; use std::sync::atomic::Ordering::{Acquire, Relaxed, Release}; use std::sync::Arc; #[test] fn compare_and_swap() { loom::model(|| { let num = Arc::new(AtomicUsize::new(0)); let ths: Vec<_> = (0..2) .map(|_| { let num = num.clone(); thread::spawn(move || { let mut curr = num.load(Relaxed); loop { let actual = num.compare_and_swap(curr, curr + 1, Relaxed); if actual == curr { return; } curr = actual; } }) }) .collect(); for th in ths { th.join().unwrap(); } assert_eq!(2, num.load(Relaxed)); }); } #[test] fn check_ordering_valid() { loom::model(|| { let n1 = Arc::new((AtomicUsize::new(0), AtomicUsize::new(0))); let n2 = n1.clone(); thread::spawn(move || { n1.0.store(1, Relaxed); n1.1.store(1, Release); }); if 1 == n2.1.load(Acquire) { assert_eq!(1, n2.0.load(Relaxed)); } }); } #[test] #[should_panic] fn check_ordering_invalid_1() { loom::model(|| { let n1 = Arc::new((AtomicUsize::new(0), AtomicUsize::new(0))); let n2 = n1.clone(); thread::spawn(move || { n1.0.store(1, Relaxed); n1.1.store(1, Release); }); if 1 == n2.1.load(Relaxed) { assert_eq!(1, n2.0.load(Relaxed)); } }); } #[test] #[should_panic] fn check_ordering_invalid_2() { loom::model(|| { let n1 = Arc::new((AtomicUsize::new(0), AtomicUsize::new(0))); let n2 = n1.clone(); thread::spawn(move || { n1.0.store(1, Relaxed); n1.1.store(1, Relaxed); }); if 1 == n2.1.load(Relaxed) { assert_eq!(1, n2.0.load(Relaxed)); } }); }