#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x()
{
x.store(true,std::memory_order_seq_cst); // 1
}
void write_y()
{
y.store(true,std::memory_order_seq_cst); // 2
}
void read_x_then_y()
{
while(!x.load(std::memory_order_seq_cst)); // 3
if(y.load(std::memory_order_seq_cst)) // 4
z;
}
void read_y_then_x()
{
while(!y.load(std::memory_order_seq_cst)); // 5
if(x.load(std::memory_order_seq_cst)) // 6
z;
}
int main() {
x=false;
y=false;
z=0;
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join();
b.join();
c.join();
d.join();
assert(z.load()!=0);
}
In the book C Concurrency in Action, the author gives this example when talking about suquential consistency, and says assert
can never fire, because
either [1] or [2] must happen first...and if one thread sees x==true and then subsequently sees y==false, this implies that the store to x occurs before the store to y in this total order.
I understant there is a global total order with all sequentially consistent atomic operations, and if one thread sees x == true, that means operation 1 synchronozies with operation 3, and also happens before 3, but my question is if that thread subsequently sees y == false, why it implies 1 happens before 2? is it possible that operation 2 happens before 1 but operation 4 doesn't see that value change?
CodePudding user response:
is it possible that operation 2 happens before 1 but operation 4 doesn't see that value change?
It is important to be careful about the terminology here. What you refer to here as "happens before" is not the happens-before relation used in the description of the memory model. What you mean here is occurs before in the total order of sequentially-consistent operations.
Suppose we write X < Y
to mean that operation X
occurs before operation Y
in that total order. You consider the case 2 < 1
. In order for 4
to observe the value before the store we also need 4 < 2
. There is also a condition that 3
observes the stored value, otherwise 4
is never reached, so also 1 < 3
. Lastly we have that 3
is sequenced-before 4
and the total order must be consistent with that, so also 3 < 4
.
All in all:
2 < 1
4 < 2
1 < 3
3 < 4
If you now try to create a total order of 1, 2, 3, 4
satisfying these conditions, you will see that it can't work. For a proof see that 2 < 1
and 1 < 3
imply 2 < 3
, which together with 3 < 4
implies 2 < 4
. That contradicts 4 < 2
.
There is no total order satisfying the conditions and therefore this is not a possible outcome. 4
must be seeing the value after the store which is in fact what the chain I used above deduced as 4 < 2
. (If you check carefully replacing the condition 4 < 2
with 2 < 4
in the above does not yield any other contradictions and so you can also find a total order actually satisfying them all.)