Clarification on the applicability of compile-time optimization to astruct variable which encompasse

J

Joshua Maurice

Am 07.07.2012 01:58, schrieb Joshua Maurice:


No, this is misleading. volatile alone is not sufficient to warrant data
consistency between threads, but is necessary. volatile and _Atomic are
complementary specifications that *both* are needed if you want to make
sure that a thread always uses the latest stored value of a variable. If
you have

static int _Atomic a = ATOMIC_VAR_INIT(23);
if (tester)
for (;;) printf("current value is %d\n", a);

The compiler is allowed to change the loop into something equivalent to

{
int tmp = a; // do an atomic_load operation here
for (;;) printf("current value is %d\n", tmp);
}

and thus always print the same value.

static int _Atomic volatile a = ATOMIC_VAR_INIT(23);

would assure that each execution of printf would see an updated value.

(Let's assume you were talking about C11.) You are simply wrong. That
is not what the standard says. This is not what people on the
standards committee are saying. That is not what compile writers are
implementing. This is not what the experts are saying. volatile is
useless for threading code by the C11 standard. Entirely useless for
inter-thread communication.

However, having said that, your example is an interesting one. The
specific rule which disallows the above compiler transformation is an
obscure one, and not one of my favorites. I've tried to discuss this
very issue on comp.std.c++, with no replies IIRC. C11 threading, being
largely just a copy of C++11 threading, has the rule in question. In
the draft I have lying around of C11, n1570, the rule is:

n1570: 7.17.3 Order and consistency / 16
Implementations should make atomic stores visible to atomic loads
within a reasonable amount of time.

That rule disallows the above transformation. The only reasonable
reading of that rule is to prevent compiler transformations like the
one above.

There's also one other new obscure rule, again copied from C++11 to
C11, which has some relevance here.

n1570: 6.8.5 Iteration statements / 6
An iteration statement whose controlling expression is not a constant
expression, that performs no input/output operations, does not access
volatile objects, and performs no synchronization or atomic operations
in its body, controlling expression, or (in the case of a for
statement) its expression-3, may be assumed by the implementation to
terminate.

This generated a lot of discussion on the C++ newsgroups. In short,
this says:
is now undefined behavior. I think I dislike the wording of this one
even more than the earlier rule. However, going with the "spirit" of
this rule, I might argue that above compiler transformation is
disallowed; if you're not allowed to make a non-terminating loop with
a constant controlling expression, then the compiler probably
shouldn't be allowed to make one either. Still, I want to emphasize
that reading is merely IMHO, whereas "7.17.3 Order and consistency /
16" much less ambiguously disallows the above compiler
transformation.

For further reading, see:
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2016.html
http://msdn.microsoft.com/en-us/library/12a04hfd.aspx
http://kernel.org/doc/Documentation/volatile-considered-harmful.txt
http://software.intel.com/en-us/blo...lmost-useless-for-multi-threaded-programming/
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
http://kerneltrap.org/Linux/Volatile_Superstition
The C++11 and C11 standards.
 
J

Jens Gustedt

Am 08.07.2012 01:19, schrieb Joshua Maurice:
(Let's assume you were talking about C11.)

Sure I was, _Atomic only comes with C11
You are simply wrong. That
is not what the standard says. This is not what people on the
standards committee are saying. That is not what compile writers are
implementing. This is not what the experts are saying. volatile is
useless for threading code by the C11 standard. Entirely useless for
inter-thread communication.

Then read the example I gave again :)
However, having said that, your example is an interesting one. The
specific rule which disallows the above compiler transformation is an
obscure one, and not one of my favorites. I've tried to discuss this
very issue on comp.std.c++, with no replies IIRC. C11 threading, being
largely just a copy of C++11 threading, has the rule in question. In
the draft I have lying around of C11, n1570, the rule is:

n1570: 7.17.3 Order and consistency / 16
Implementations should make atomic stores visible to atomic loads
within a reasonable amount of time.

The "should" makes it clearly a non-normative part of the standard and
leaves it to the appreciation of the compiler implementor what
"reasonable amount of time" is.

If the implementor decides that "reasonable amount of time" is 1
milli-second, the loop could be implemented to only do an update each
milli-second.

Said otherwise, there can be no guarantee that for the non-volatile
case an implementation decides to skip a load operation somewhere that
would bring a fresh value into some other thread.
That rule disallows the above transformation.

no, I just suggest that a compiler shouldn't do it.
The only reasonable
reading of that rule is to prevent compiler transformations like the
one above.

to discourage, not to prevent

Jens
 
J

James Kuyper

Am 08.07.2012 01:19, schrieb Joshua Maurice: ....
n1570: 7.17.3 Order and consistency / 16
Implementations should make atomic stores visible to atomic loads
within a reasonable amount of time.

The "should" makes it clearly a non-normative part of the standard and
leaves it to the appreciation of the compiler implementor what
"reasonable amount of time" is.

While the "should" is a strong hint, it's the fact that it's in a
"recommended practice" section which makes it perfectly clear that this
is optional.
 
J

James Kuyper

On 07/07/2012 04:04 PM, Uncle Steve wrote:
....
I realize that c.l.c. is for discussions about the C language, without
necessary reference to any particular implementation. Nevertheless,
with threads supported by C11 I would imagine some discussion might be
allowed.

No one can disallow anything in an unmoderated newsgroup like this.

However, if you insist on discussing pthreads rather than C11 threads,
c.l.c is not as a good a place to have a well-informed discussion as
comp.programming.threads. If you deliberately want to get less than the
best possible answers to your question, continue posting here; but if
that is your goal, then surely a newsgroup completely unrelated to any
kind of computer programming, such as alt.fun.with.steve, would serve
that goal even better than this newsgroup?
 
P

Philip Lantz

Joshua said:
There's also one other new obscure rule, again copied from C++11 to
C11, which has some relevance here.

n1570: 6.8.5 Iteration statements / 6
An iteration statement whose controlling expression is not a constant
expression, that performs no input/output operations, does not access
volatile objects, and performs no synchronization or atomic operations
in its body, controlling expression, or (in the case of a for
statement) its expression-3, may be assumed by the implementation to
terminate.

This generated a lot of discussion on the C++ newsgroups. In short,
this says:
is now undefined behavior.

The controlling expression of that loop is a constant expression--
footnote 156 makes this clear--so it doesn't meet the prerequisites for
paragraph 6.8.5p6 to apply.

Furthermore, even if the paragraph did apply, it doesn't make the
behavior undefined, it just allows the compiler to remove the loop if it
doesn't detect any side effects.
 
P

Philip Lantz

Uncle said:
Currently I'm developing on x86_64 and x86, and I chose to
use "lock incl %0" and then inspect the result to detect collisions.
It is obviously very fast, and I can control how long a thread will
spin on the lock before sleeping. I have yet to investigate whether I
need to use a different instruction for the 64-bit arch.

You may not want to use inc, because then you can't discover the result
without reading it again, so you lose atomicity. I recommend using xadd
to add 1, it atomically returns the previous value in a register.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,008
Latest member
HaroldDark

Latest Threads

Top