use loom::sync::atomic::{ AtomicUsize, AtomicBool, Ordering };
use loom::thread;
use loom::sync::Arc;
use loom::cell::UnsafeCell;
#[test]
fn requires_seqcst() {
loom::model(|| {
let x = Arc::new(AtomicBool::new(false));
let y = Arc::new(AtomicBool::new(false));
let z = Arc::new(AtomicUsize::new(0));
// Two threads set x and y to true simultaneously:
let x1 = Arc::clone(&x);
let h1 = thread::spawn(move || x1.store(true, Ordering::SeqCst));
let y1 = Arc::clone(&y);
let h2 = thread::spawn(move || y1.store(true, Ordering::SeqCst));
// Next, two threads (the main thread and a spawned one, because in
// loom we're limited to 4 threads max) read from either x then y, or
// y then x, incrementing a counter if, when the fst is true, the snd is
// also true.
fn reader(fst: Arc<AtomicBool>, snd: Arc<AtomicBool>, cnt: Arc<AtomicUsize>) {
while !fst.load(Ordering::SeqCst) {
thread::yield_now();
}
if snd.load(Ordering::SeqCst) {
cnt.fetch_add(1, Ordering::SeqCst);
}
}
let (x2, y2, z2) = (Arc::clone(&x), Arc::clone(&y), Arc::clone(&z));
let h3 = thread::spawn(move || reader(x2,y2,z2)); // note ordering: fst is x, snd is y
let (x3, y3, z3) = (Arc::clone(&x), Arc::clone(&y), Arc::clone(&z));
reader(y3,x3,z3); // note ordering: fst is y, snd is x
h1.join().unwrap();
h2.join().unwrap();
h3.join().unwrap();
assert_ne!(z.load(Ordering::Relaxed), 0);
})
}
I've had success running some things that feel more branchy/complex than this in loom, but I left this test running for a couple of hours and it eventually panicked, resulting in console output like:
================== Iteration 136320000 ==================
================== Iteration 136340000 ==================
================== Iteration 136360000 ==================
================== Iteration 136380000 ==================
================== Iteration 136400000 ==================
================== Iteration 136420000 ==================
thread 'test_seqcst::requires_seqcst' panicked at 'Model exeeded maximum number of branches. This is often caused by an algorithm requiring the processor to make progress, e.g. spin locks.', /Users/james.wilson/.cargo/registry/src/github.com-1ecc6299db9ec823/loom-0.4.0/src/rt/path.rs:199:13
test test_seqcst::requires_seqcst ... FAILED
I tried replacing all of the Ordering::SeqCsts with Ordering::Relaxed to see whether it would run faster or something, but it seemed to keep going for many millions of iterations before I gave up.
Is there a way to have this example (or something practically the same) run in a reasonable number of iterations?
Is this a sign of a bug in loom, or is something about my code leading to much more complexity than I had assumed?
(also a nit: exeeded appears to be a typo in the panic)
The below code is a rust port of the Sequential Consistency example at the bottom of https://en.cppreference.com/w/cpp/atomic/memory_order which fails to run in loom:
I've had success running some things that feel more branchy/complex than this in loom, but I left this test running for a couple of hours and it eventually panicked, resulting in console output like:
I tried replacing all of the
Ordering::SeqCst
s withOrdering::Relaxed
to see whether it would run faster or something, but it seemed to keep going for many millions of iterations before I gave up.Is there a way to have this example (or something practically the same) run in a reasonable number of iterations? Is this a sign of a bug in loom, or is something about my code leading to much more complexity than I had assumed?
(also a nit:
exeeded
appears to be a typo in the panic)