Reputation: 23
There is a part in the C++ standard about multi-threading memory model that I don't understand.
A visible side effect A on a scalar object or bit-field M with respect to a value computation B of M satisfies the conditions:
A happens before B and
there is no other side effect X to M such that A happens before X and X happens before B.
The value of a non-atomic scalar object or bit-field M, as determined by evaluation B, shall be the value stored by the visible side effect A.
And also according to the C++ standard, a "happens before" relationship between threads must be established by "synchronizes with" or "is dependency-ordered before", so a "happens before" relationship will not be established without inter-thread synchronization.
Now suppose there are two threads T1 and T2, both started by the main thread and never do any synchronization with each other (so there would not be any "happens before" relationships established between T1 and T2). If T1 writes to a non-atomic variable M, then according to the quote above, T2 should never see M modified by T1, because there is no "happens before" relationship between T1 and T2.
Instead, T2 has "synchronizes with" relationship established with the main thread at the time T2 starts, so T2 should see the value of M set by the main thread before it was started by the main thread, because there is a "happens before" relationship between the main thread and T2.
Right? However I did an experiment on my machine and it was not the case. What is wrong?
Upvotes: 2
Views: 639
Reputation: 1292
In addition to the perspective presented by Nicol Bolas in his answer, I would point out the following error of conclusion in the OP's question.
T2 should never see M modified by T1, because there is no "happens before" relationship between T1 and T2
The quoted section in the question intuitively means that if
then
Side effect of A is visible to B (let's call this AVTB)
Succinctly,
If (AHB and NXBAB) is true then it implies AVTB is also true
According to boolean algebra, and even basic common sense, this does not mean that
If (AHB and NXBAB) is not true then it implies AVTB is also not true
In general, if A does not happen before B then the side effects of A are not guaranteed to be visible to B. They may still be visible, in sane and insane ways, and that's what the Undefined Behaviour in Nicol Bolas's answer is about.
Upvotes: 0
Reputation: 473447
T1 writes to a non-atomic variable M, then according to the quote above, T2 should never see M modified by T1
Consider the following:
Two actions are potentially concurrent if
they are performed by different threads, or
they are unsequenced, at least one is performed by a signal handler, and they are not both performed by the same signal handler invocation.
T2's read of M and T1's write to M are "potentially concurrent". Next:
Two expression evaluations conflict if one of them modifies a memory location and the other one reads or modifies the same memory location.
T2's read of M conflicts with T1's write to M. So these "potentially concurrent" actions conflict.
Lastly, we come to:
The execution of a program contains a data race if it contains two potentially concurrent conflicting actions, at least one of which is not atomic, and neither happens before the other, except for the special case for signal handlers described below. Any such data race results in undefined behavior.
T2's read of M does not happen before T1's write to M, nor does T1's write to M happen before T2's read of M. Therefore, you have a data race.
And data races are undefined behavior. It's not that T2 won't see the write to M; it's that it could see anything: the old value, the new value, some third value, nasal daemons issuing forth, anything.
Upvotes: 2