Someone also asked this in rust lang discord server but it was a bit unclear to me...
Can someone please explain how this fence helps to make sure that nothing is accessing the shared allocation? It's a bit confusing because with Release and Acquire ordering one should be loading the Released value to make sure that an happens-before relationship was established...
Does this fence apply Acquire ordering to the fetching part of fetch_sub when the counter goes from 0 to 1?
impl<T> Drop for Arc<T> {
fn drop(&mut self) {
if self.data().ref_count.fetch_sub(1, Release) == 1 {
fence(Acquire);
unsafe {
drop(Box::from_raw(self.ptr.as_ptr()));
}
}
}
}
It's going to 0. (I assume you intended that.) (No code will ever read 0 though.)
The data could have been modified in another thread (such as one what called drop before so setting counter to 1.)
The Acquire ensures this thread sees the same data as the data modifying thread (that set counter to 1.)
The thread has already read the ref_count as being 1 and set it to 0 at point of fence call. It is other memory that has been associated with the ref_count being set to 1 by Release that this thread is now allowed rely upon.
In my understanding, fence synchronizes with all previous fetch_sub(1, Release)s. In other words, if another thread has modified the guarded data, fence makes sure that we will see those changes (which is needed for correct execution of Drop). Note that we do not need to synchronize with changes performed by the current thread.
We could've used fetch_sub(1, AcqRel) instead without any fence, but it would mean that Acquire synchronization is performed on each decrement, which is somewhat wasteful since we only need it when the counter reaches 0.
So it's just a micro-optimization for targets with weak memory model.
An important caveat is that with atomic operations (as opposed to fences) synchronize only when Acquire/Release pair is executed on the same memory, i.e. a.store(Release) and b.load(Acquire) do not synchronize with each other if a and b point to different atomics. It's better to think about atomics in terms of "happened-before" relationships and potential memory operation reorderings.