In this lesson, you will learn how to use memory fences to enforce the order of operations and ensure your data remains consistent across multiple CPU cores.
The Illusion of Sequential Execution
When you write code, you assume lines execute in the exact order you wrote them. However, modern CPUs and compilers are "out-of-order" machines. To optimize performance, they may reorder memory operations, and since each CPU core has its own local cache, changes made by one core might not immediately become visible to another. This is the challenge of cache coherence.
Enter Memory Barriers (Fences)
A memory barrier, or "fence," is a synchronization instruction that tells the CPU and the compiler: "Stop! Do not reorder instructions across this line."
In Rust, we use std::sync::atomic::fence to enforce these boundaries. Fences do not perform any data operations themselves; they simply create a wall that memory effects cannot cross.
A Practical Illustration
Imagine a common flag pattern used for signaling:
use std::sync::atomic::{fence, AtomicBool, Ordering};
static mut DATA: u64 = 0;
static READY: AtomicBool = AtomicBool::new(false);
// Core 1: Writing data
unsafe {
DATA = 42;
// Ensure the write to DATA completes BEFORE the flag is set
fence(Ordering::Release);
READY.store(true, Ordering::Relaxed);
}
// Core 2: Reading data
if READY.load(Ordering::Relaxed) {
// Ensure we don't read DATA until we confirm READY is true
fence(Ordering::Acquire);
unsafe { println!("{}", DATA); }
}
Without the Release fence, the CPU might store true in READY before the value 42 has finished being written to the actual memory location. Without the Acquire fence, Core 2 might speculatively read the value of DATA before it even checks the READY flag.
The Ordering::Release ensures all previous memory operations are "published" before the fence, and Ordering::Acquire ensures all subsequent memory operations see the state as it existed at the time of the corresponding Release. By placing these fences, you prevent the hardware from "cheating" and breaking your logic.
Key Takeaway: Memory barriers (fences) are the essential tools that force the CPU to respect the intended order of memory access, bridging the gap between local cache states and global memory consistency.