Does the C++11 memory model allow hoisting relaxed

2019-02-21 11:31发布

问题:

Consider the following code:

#include <atomic>

extern std::atomic<int> i;

void f(void)
{
  while (!i.load(std::memory_order_relaxed))
      ;
}

I'm looking for a citation from the C++11 standard that says that the compiler is not allowed to transform the loop into

  if (!i.load(std::memory_order_relaxed)) {
    while (1)
      ;
  }

I've seen some discussion here but nothing conclusive.

Edit: A previous version of this post called an extern function inside the loop.

Edit 2: For motivation: The book "Effective Java" says that the HotSpot VM performs the following transformation:

while (!done)
    i++;

to

if (!done)
    while (true)
        i++;

even though it's perfectly defined behavior for another thread to change the done variable concurrently.

回答1:

Forget about relaxed, there's no guarantee that an atomic store ever become visible to an atomic load in a different thread. The best you get is the normative encouragement in [atomics.order]/12 (and analogous wording in [intro.progress]/18):

Implementations should make atomic stores visible to atomic loads within a reasonable amount of time.

...which is not a requirement.

(C11 has identical wording in §7.11.3/16)

Since hoisting the load leads to behavior indistinguishable from a non-hoisted load where the store never becomes visible, and since the latter is conforming, an implementation is allowed by the as-if rule to hoist the load regardless of the memory order used.