c++11 std::atomic and memory_order_relaxed

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: c++11 std::atomic and memory_order_relaxed

Post by Rein Halbersma »

bob wrote:
kbhearn wrote:Technically the quote in the first example still almost exists in the current working draft.

http://isocpp.org/files/papers/N3690.pdf

'discouraged from allowing' changed to 'should not allow'. Regardless, my question was answered a couple dozen postings ago as to how it doesn't break the requirements put forth in the standard. The elaborations that in practical terms it'd never happen anyway were also appreciated. I'd ask that the circle of insults stop but i think the two of you must rather enjoy it.
Seems that "should not allow" is pretty clear? It would seem to me if it says "should not allow" and your compiler allows that, it violates the standard?

Which makes perfect sense since current hardware can not pull this off...
The latest draft C++ Standard is N3797, which states in 29.3 Order and consistency [atomics.order]/9:
9 Implementations should ensure that no “out-of-thin-air” values are computed that circularly depend on their
own computation.
[ Note: For example, with x and y initially zero,

Code: Select all

// Thread 1:
r1 = y.load(memory_order_relaxed);
x.store(r1, memory_order_relaxed);

// Thread 2:
r2 = x.load(memory_order_relaxed);
y.store(r2, memory_order_relaxed);
should not produce r1 == r2 == 42, since the store of 42 to y is only possible if the store to x stores 42,
which circularly depends on the store to y storing 42. Note that without this restriction, such an execution
is possible. — end note ]
It is important to know how to read an ISO Standard. In particular, appendix H.2 of the ISO/IEC Directives states that the wording "should not" is to be interpreted as "it is not recommended that" or "ought not to". In fact, H.2 states that
The verbal forms shown in Table H.2 shall be used to indicate that among several possibilities
one is recommended as particularly suitable, without mentioning or excluding others, or that a
certain course of action is preferred but not necessarily required, or that (in the negative form)
a certain possibility or course of action is deprecated but not prohibited.
This is different from "shall not", which is to be interpreted as "is not allowed [permitted] [acceptable] [permissible]", "is required to be not", "is required that … be not", or "is not to be".
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: c++11 std::atomic and memory_order_relaxed

Post by bob »

Seems like one of the root faults with the standards, to me.

You either allow something or you don't. In the current discussion, the x=y=42 example can not happen with any past or existing hardware. So all that is left is for the compiler to do an unsafe optimization (speculative store) which breaks the program. The standard says "it should not allow this." If that means "but it can if it chooses" then the standard is broken. A standard should say what is allowed, and what is not allowed. It should not include insipid statements that basically say "this should not be done, but doing so does not violate the standard." That kind of nonsense is why software engineering is where it is today...
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: c++11 std::atomic and memory_order_relaxed

Post by Rein Halbersma »

bob wrote:Seems like one of the root faults with the standards, to me.

You either allow something or you don't. In the current discussion, the x=y=42 example can not happen with any past or existing hardware. So all that is left is for the compiler to do an unsafe optimization (speculative store) which breaks the program. The standard says "it should not allow this." If that means "but it can if it chooses" then the standard is broken. A standard should say what is allowed, and what is not allowed. It should not include insipid statements that basically say "this should not be done, but doing so does not violate the standard." That kind of nonsense is why software engineering is where it is today...
It's a little bit more complicated than what you think.

The current wording in N3797 is already a big step up from older draft versions of the Standard. E.g, note that the sentence "Implementations should ensure that "no-out-of-thin-air"..." is outside the brackets "[Note: For example... -- end note ]". That makes the "no-out-of-thin-air" a normative encouragement, whereas the note (which was the only part in older draft Standards) is only an informative encouragement.

The next step up would be that the Standard will make it a normative requirement instead of "only" a normative encouragement. However, the author of N3786 notes that
The core problem here is that we do not know (after 10 years of failed attempts, originally in a Java context) how to precisely state this requirement without strengthening it so that it impacts code performance. (See N3710 for details.).
In other words, the Committee is not unsympathetic to what you write above, and would also like to make the Standard as strict as possible, however without unduly affecting performance. In some cases, like the above one, they think they have enough reasons not to do that.
syzygy
Posts: 5566
Joined: Tue Feb 28, 2012 11:56 pm

Re: c++11 std::atomic and memory_order_relaxed

Post by syzygy »

Rein Halbersma wrote:In other words, the Committee is not unsympathetic to what you write above, and would also like to make the Standard as strict as possible, however without unduly affecting performance. In some cases, like the above one, they think they have enough reasons not to do that.
What I think also plays a role is that simply outlawing a few examples only addresses a few particular symptoms and does little to cure the problem. Forbidding a few examples cannot replace precise requirements.
Rein Halbersma
Posts: 741
Joined: Tue May 22, 2007 11:13 am

Re: c++11 std::atomic and memory_order_relaxed

Post by Rein Halbersma »

syzygy wrote:
Rein Halbersma wrote:In other words, the Committee is not unsympathetic to what you write above, and would also like to make the Standard as strict as possible, however without unduly affecting performance. In some cases, like the above one, they think they have enough reasons not to do that.
What I think also plays a role is that simply outlawing a few examples only addresses a few particular symptoms and does little to cure the problem. Forbidding a few examples cannot replace precise requirements.
Agreed in general, but in this case, the subject is so enormously complicated that even after a decade experience, people have been unable to come up with more precise requirements!
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: c++11 std::atomic and memory_order_relaxed

Post by bob »

Rein Halbersma wrote:
bob wrote:Seems like one of the root faults with the standards, to me.

You either allow something or you don't. In the current discussion, the x=y=42 example can not happen with any past or existing hardware. So all that is left is for the compiler to do an unsafe optimization (speculative store) which breaks the program. The standard says "it should not allow this." If that means "but it can if it chooses" then the standard is broken. A standard should say what is allowed, and what is not allowed. It should not include insipid statements that basically say "this should not be done, but doing so does not violate the standard." That kind of nonsense is why software engineering is where it is today...
It's a little bit more complicated than what you think.

The current wording in N3797 is already a big step up from older draft versions of the Standard. E.g, note that the sentence "Implementations should ensure that "no-out-of-thin-air"..." is outside the brackets "[Note: For example... -- end note ]". That makes the "no-out-of-thin-air" a normative encouragement, whereas the note (which was the only part in older draft Standards) is only an informative encouragement.

The next step up would be that the Standard will make it a normative requirement instead of "only" a normative encouragement. However, the author of N3786 notes that
The core problem here is that we do not know (after 10 years of failed attempts, originally in a Java context) how to precisely state this requirement without strengthening it so that it impacts code performance. (See N3710 for details.).
In other words, the Committee is not unsympathetic to what you write above, and would also like to make the Standard as strict as possible, however without unduly affecting performance. In some cases, like the above one, they think they have enough reasons not to do that.
I don't think that the choice (a) efficient (b) absolutely correct; has to be either/or, and in particular, NOTHING should overwrite the importance of (b). x=y=42 is utter nonsense, everyone knows it is utter nonsense, the standards committee could simply say "this is not allowable." It won't affect any compiler today that is not broken, because no compiler would speculatively write to memory in an environment where threads are possible, without first handling the control dependency.

I don't see the point where a standard says something that can not happen in hardware is, according to the standard, permissible for the compiler to do. Should the compiler REALLY be allowed to break a program intentionally?
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: c++11 std::atomic and memory_order_relaxed

Post by bob »

syzygy wrote:
Rein Halbersma wrote:In other words, the Committee is not unsympathetic to what you write above, and would also like to make the Standard as strict as possible, however without unduly affecting performance. In some cases, like the above one, they think they have enough reasons not to do that.
What I think also plays a role is that simply outlawing a few examples only addresses a few particular symptoms and does little to cure the problem. Forbidding a few examples cannot replace precise requirements.
Simple to say "control dependencies must be honored in ALL circumstances where threads are possible."
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: c++11 std::atomic and memory_order_relaxed

Post by bob »

Rein Halbersma wrote:
syzygy wrote:
Rein Halbersma wrote:In other words, the Committee is not unsympathetic to what you write above, and would also like to make the Standard as strict as possible, however without unduly affecting performance. In some cases, like the above one, they think they have enough reasons not to do that.
What I think also plays a role is that simply outlawing a few examples only addresses a few particular symptoms and does little to cure the problem. Forbidding a few examples cannot replace precise requirements.
Agreed in general, but in this case, the subject is so enormously complicated that even after a decade experience, people have been unable to come up with more precise requirements!
I don't buy the explanation "unable to come up with..." This type of issue, AKA "a simple control dependency" is well-defined in computer hardware. So why let the standards guys off the hook when the hardware guys can get it right with no fanfare of drama...

My Hennessy and Patterson text I use in the computer architecture course explicitly addresses control dependencies among others. It is not an unknown issue.
Michel
Posts: 2272
Joined: Mon Sep 29, 2008 1:50 am

Re: c++11 std::atomic and memory_order_relaxed

Post by Michel »

I don't buy the explanation "unable to come up with..." This type of issue, AKA "a simple control dependency" is well-defined in computer hardware. So why let the standards guys off the hook when the hardware guys can get it right with no fanfare of drama...
If it so easy to you why don't you make a proposal to the standards people?

This document gives a long explanation why the issues are hard:
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: c++11 std::atomic and memory_order_relaxed

Post by bob »

Michel wrote:
I don't buy the explanation "unable to come up with..." This type of issue, AKA "a simple control dependency" is well-defined in computer hardware. So why let the standards guys off the hook when the hardware guys can get it right with no fanfare of drama...
If it so easy to you why don't you make a proposal to the standards people?

This document gives a long explanation why the issues are hard:
Did you read it. Specifically this part:
Note: The recommendation similarly disallows r1 == r2 == 42 in the following example, with x and y initially zero:

// Thread 1:
r1 = x.load(memory_order_relaxed);
if (r1 == 42) y.store(r1, memory_order_relaxed);
// Thread 2:
r2 = y.load(memory_order_relaxed);
if (r2 == 42) x.store(42, memory_order_relaxed);
However, implementations should not allow such behavior. -end note
Seems to DIRECTLY fix the issue... So I fail to see why it is "so hard to fix" when the above directly fixes it. The hardware can't possibly do the above by itself, it already understands the problem and solves it correctly. So we are left with the compiler specification being so poorly written that the above could be done by the compiler, producing a bogus result. The above change simply closes the door. It wasn't THAT hard either.