pub fn compiler_fence(order: Ordering)
Expand description
A “compiler-only” atomic fence.
Like fence
, this function establishes synchronization with other atomic operations and
fences. However, unlike fence
, compiler_fence
only establishes synchronization with
operations in the same thread. This may at first sound rather useless, since code within a
thread is typically already totally ordered and does not need any further synchronization.
However, there are cases where code can run on the same thread without being ordered:
- The most common case is that of a signal handler: a signal handler runs in the same thread
as the code it interrupted, but it is not ordered with respect to that code.
compiler_fence
can be used to establish synchronization between a thread and its signal handler, the same way thatfence
can be used to establish synchronization across threads. - Similar situations can arise in embedded programming with interrupt handlers, or in custom
implementations of preemptive green threads. In general,
compiler_fence
can establish synchronization with code that is guaranteed to run on the same hardware CPU.
See fence
for how a fence can be used to achieve synchronization. Note that just like
fence
, synchronization still requires atomic operations to be used in both threads – it is
not possible to perform synchronization entirely with fences and non-atomic operations.
compiler_fence
does not emit any machine code, but restricts the kinds of memory re-ordering
the compiler is allowed to do. compiler_fence
corresponds to atomic_signal_fence
in C and
C++.
§Panics
Panics if order
is Relaxed
.
§Examples
Without compiler_fence
, the assert_eq!
in following code
is not guaranteed to succeed, despite everything happening in a single thread.
To see why, remember that the compiler is free to swap the stores to
IMPORTANT_VARIABLE
and IS_READY
since they are both
Ordering::Relaxed
. If it does, and the signal handler is invoked right
after IS_READY
is updated, then the signal handler will see
IS_READY=1
, but IMPORTANT_VARIABLE=0
.
Using a compiler_fence
remedies this situation.
use std::sync::atomic::{AtomicBool, AtomicUsize};
use std::sync::atomic::Ordering;
use std::sync::atomic::compiler_fence;
static IMPORTANT_VARIABLE: AtomicUsize = AtomicUsize::new(0);
static IS_READY: AtomicBool = AtomicBool::new(false);
fn main() {
IMPORTANT_VARIABLE.store(42, Ordering::Relaxed);
// prevent earlier writes from being moved beyond this point
compiler_fence(Ordering::Release);
IS_READY.store(true, Ordering::Relaxed);
}
fn signal_handler() {
if IS_READY.load(Ordering::Relaxed) {
assert_eq!(IMPORTANT_VARIABLE.load(Ordering::Relaxed), 42);
}
}