If you've been living under a rock for the past ten years--or if you're coming from old-style C--you might ask, "What's wrong with the volatile keyword? When I want to make sure some access really hits memory, I make sure it's done volatile."
The official semantics of volatile are that volatile accesses are evaluated strictly according to the rules of the abstract machine, which means, more or less, that the compiler is not allowed to reorder them or combine multiple accesses into one. For example, the compiler cannot assume that the value of x remains the same between these two loads; it must generate machine code that performs two loads, one on either side of the store to y:
volatile int& x = memory_mapped_register_x(); ...