So I've been trying to muck around with atomics today, but I've hit a bizarre issue where if I update an AtomicU32
in the first iteration of a loop, and then try to access it in the second iteration, the second iteration only observes the initial value.
The code is as follows, and would ideally not panic.
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering;
use std::num::NonZeroU32;
fn main() {
let aonz = AtomicOptionNonZeroU32::new(None);
assert_eq!(aonz.get(), None);
let val = NonZeroU32::new(13).unwrap();
let mut first = true;
loop {
if first {
aonz.set(Some(val));
assert_eq!(aonz.get(), Some(val));
first = false;
} else {
assert_eq!(aonz.get(), Some(val));
assert_eq!(aonz.take(), Some(val));
assert_eq!(aonz.get(), None);
}
}
}
#[derive(Debug)]
struct AtomicOptionNonZeroU32(AtomicU32);
impl AtomicOptionNonZeroU32 {
fn new(ptr: Option<NonZeroU32>) -> Self {
Self(AtomicU32::new(ptr.map(u32::from).unwrap_or(0)))
}
fn get(&self) -> Option<NonZeroU32> {
NonZeroU32::new(self.0.load(Ordering::Acquire))
}
fn set(&self, ptr: Option<NonZeroU32>) {
self.0
.store(ptr.map(u32::from).unwrap_or(0), Ordering::Release);
}
fn take(&self) -> Option<NonZeroU32> {
NonZeroU32::new(self.0.swap(0, Ordering::SeqCst))
}
}