Atomic fusion

Finally, one should realize that while atomic operations do prevent certain optimizations, they are not somehow immune to all of them. The optimizer can do fairly mundane things, such as replacing foo.fetch_and(0) with foo = 0, but it can also produce surprising results. Consider:

while (tmp = foo.load(memory_order_relaxed)) {
    doSomething(tmp);
}

Since relaxed loads provide no ordering guarantees, the compiler is free to unroll the loop as much as it pleases, perhaps into:

while (tmp = foo.load(memory_order_relaxed)) {
    doSomething(tmp);
    doSomething(tmp);
    doSomething(tmp);
    doSomething(tmp);
}

If “fusing” reads or writes like this is unacceptable, we must prevent it with volatile casts or incantations like asm volatile("" ::: "memory").1 The Linux kernel provides READ_ONCE() and WRITE_ONCE() macros for this exact purpose.2

2

See n4374 and the kernel’s rwonce.h for details.