Acquire semantics prevent memory operations after an acquire operation from being reordered before it. They are normally paired with release semantics: a writer publishes its earlier updates with a release operation, and a reader that observes that publication through an acquire operation can then read those updates. An acquire barrier combines the ordering provided by LoadLoad and LoadStore barriers. section 8.4.1 section 8.4.3
A completion flag
Suppose one thread stores 1 in value, then sets done to true. Another thread reads done before reading value. With relaxed ordering on both variables, it can observe done == true and value == 0: the flag appears complete while the result is stale. Store true to done with Release and load done with Acquire. If that load observes true, the subsequent read of value sees the earlier update. Reading false makes no such claim about whether the update has happened. section 8.4.3
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::thread;
fn main() {
for _ in 0..1000000 {
let value = Arc::new(AtomicUsize::new(0));
let done = Arc::new(AtomicBool::new(false));
let value1 = value.clone();
let done1 = done.clone();
let t1 = thread::spawn(move || {
value1.store(1, Ordering::Relaxed);
done1.store(true, Ordering::Release);
});
let t2 = thread::spawn(move || {
let done = done.load(Ordering::Acquire);
let value = value.load(Ordering::Relaxed);
println!("value = {}, done = {}", value, done);
});
t1.join().unwrap();
t2.join().unwrap();
}
}
The Rust listing puts Release on the writer’s done store and Acquire on the reader’s done load; value remains relaxed. section 8.4.3
In a bounded single-producer, single-consumer queue, the producer writes an array slot before publishing the updated back index with Release. The consumer loads back with Acquire before reading that slot. The front index uses the corresponding ordering in the opposite direction. Loads of an index by the thread that alone updates it can remain relaxed when that thread needs no ordering guarantee from the load. Acquire and release provide the needed ordering without full mutual exclusion; the compiler supplies the appropriate implementation for the target architecture. section 8.6 section 8.4.1




