On Tue, Jun 3, 2014 at 1:38 AM, Giovanni Piero Deretta
This is of course only one (the one that I'm familiar with) of the optimizations that can break seemly correct code, but there are others (like aggressive expression reduction) that not even require PGO.
I see. So there's basically no way I can protect myself from such code injection. The problem is further complicated by the fact that not all code is "mine" in case of atomic<> implementation.
The authors of the C++ memory model knew about this issue and added quite complex rules to prevent the compiler from breaking dependencies. Compilers that may perform dependency breaking optimizations, are required to preserve consume ordering at function calls boundaries by issuing explicit fences and upgrading the consumes to acquires. The alternative would be to require whole program compilation which is untenable. Alternatively, sprinkling the code carefully with [[carries_dependency]]supposedly can prevent the compiler from issuing the fence.
In practice implementing the required dependency tracking machinery on existing compilers has proven too hard so they issue the fence immediately when performing the initial load, so it is possible that the committee will change this part of the standard: see N4036 on the last mailing.
N4036 looks interesting, although I suspect adding another type qualifier to the language has the potential to break code, which now only accounts for const and volatile. This is more specific to C++. Also, it's not quite clear how atomic.load(consume) could return a value dep preserving-qualified type but not atomic.load(other_memory_order).
For the time being we are stuck with either load_acquire or very fragile workarounds.
Ok, so I did in Boost.Atomic. Thank you again for the most helpful comments.