0

Below is an example given in Concurrency in Action , and the author says the assert may fire, but I don't understand why.

#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x_then_y()
{
  x.store(true,std::memory_order_relaxed);
  y.store(true,std::memory_order_relaxed);
}
void read_y_then_x()
{
  while(!y.load(std::memory_order_relaxed));
  if(x.load(std::memory_order_relaxed))
  ++z;
}
int main()
{
  x=false;
  y=false;
  z=0;
  std::thread a(write_x_then_y);
  std::thread b(read_y_then_x);
  a.join();
  b.join();
  assert(z.load()!=0);
}

As far as I know, in each single thread, sequenced before also means happens before. So in thread a the store to x happens before y, which means x should be modified before y and the result x.store should be visible before y is modified.

But in this example the author says that the store between x and y could be reordered, why? Does that violate the rule of sequenced before and happens before?

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
choxsword
  • 3,187
  • 18
  • 44
  • This might explain things about relaxed ordering https://en.cppreference.com/w/cpp/atomic/memory_order#Relaxed_ordering – Sami Kuhmonen Jul 29 '18 at 13:54
  • @SamiKuhmonen sequenced before relationship does not prevent reordering? Then what's the usage of sequenced before? – choxsword Jul 29 '18 at 14:13
  • `x.store` happens-before `y.store` and `y.load` happens-before `x.load` - but `x.store` doesn't happen-before `x.load`. Happens-before relationship is not necessarily transitive in the presence of relaxed operations; that's kind of their whole point. – Igor Tandetnik Jul 29 '18 at 14:20
  • @IgorTandetnik but `y.store` happens before `while(!y.load(std::memory_order_relaxed))` , so `x.store` hapeens before `x.load`? – choxsword Jul 29 '18 at 14:21
  • The conclusion doesn't follow from the premise. Yes, `y.store` happens-before `y.load`. No, `x.store` does not happen-before `x.load`. You have a sequentially-consistent model of execution in your head - but relaxed operations violate that model; that's why they are called "relaxed", and that's why they are difficult to reason about. – Igor Tandetnik Jul 29 '18 at 14:23
  • @IgorTandetnik since `y.store` happens before `y.load==true`, and happens before relationship is trasitive, why doesn't `x.store` happens before `x.load`? – choxsword Jul 29 '18 at 14:38
  • Again, happens-before relationship is **not** in general transitive. In particular, it is not transitive in the presence of relaxed operations. Would it be too much to ask for you to read a comment in full before responding? – Igor Tandetnik Jul 29 '18 at 14:58
  • The **Concurrency in Action** says "It’s also a transitive relation: if A inter-thread happens-before B and B interthread happens-before C, then A inter-thread happens-before C.". – choxsword Jul 29 '18 at 15:02
  • *happens-before* and *inter-thread happens-before* are two different relations. Here, `y.load` does not inter-thread happens-before `x.load` (since both are on the same thread). – Igor Tandetnik Jul 29 '18 at 15:14
  • @IgorTandetnik What's the differences between happens before and inter-thread happens before? – choxsword Jul 29 '18 at 15:41
  • http://eel.is/c++draft/intro.multithread#intro.races-10 – Igor Tandetnik Jul 29 '18 at 15:45
  • @IgorTandetnik Your linkage says they are not different relations, inter-thread happens before belongs to happens before. – choxsword Jul 29 '18 at 16:14
  • 1
    They are different relations, where one is a subset of the other. The subset is transitive; the superset is not. In particular, if `A` inter-thread happens-before `B` and `B` is sequenced-before `C`, this doesn't necessarily mean that `A` happens-before `C` (even though `A` happens-before `B` and `B` happens-before `C`). – Igor Tandetnik Jul 29 '18 at 16:23

0 Answers0