use std::sync::atomic::AtomicPtr;
fn get_data() -> &'static Data {
static PTR: AtomicPtr<Data> = AtomicPtr::new(std::ptr::null_mut());
let mut p = PTR.load(Acquire);
if p.is_null() {
p = Box::into_raw(Box::new(generate_data()));
if let Err(e) = PTR.compare_exchange(
std::ptr::null_mut(), p, Release, Acquire
) {
// Safety: p comes from Box::into_raw right above,
// and wasn't shared with any other thread.
drop(unsafe { Box::from_raw(p) });
p = e;
}
}
// Safety: p is not null and points to a properly initialized value.
unsafe { &*p }
}
If I change the first PTR.load to Relaxed, what will be the effect?
It comes from Rust Atomics and Locks, but it doesn't make explanation about the first PTR.load. I don't quite understand why I can't use Relaxed here.
I think the release exchange guaranteed that the object will be fully created, so the load operation won't get older or incomplete data. And when PTR.load(Acquire) it will also happen that multiple threads may detect a null pointer in the PTR at the same time, and more than one thread may try to create and initialize the Data object. So I don't know the effect here.