volatile and barriers (especially on PPC)
Peter A. Buhr
pabuhr at plg.uwaterloo.ca
Sat Mar 12 02:59:43 GMT 2005
I removed Clark Nelson from the CC list based on Hans' suggestion. I also
removed Ashif Harji, as he is only mildly interested and I can keep him up to
date.
We all agree! We are taking the witchcraft out of it! It will
now mean something very specific and useful, that just by chance
happens to also cover all the cases it was previously allegedly
necessary too. What could be nicer?
Let's look at the C manual because C++ usually defers to C on these kinds of
issues.
Section 6.7.2 "Type Qualifiers", point 6:
An object that has volatile-qualified type may be modified in ways unknown
to the implementation or have other unknown side effects. Therefore any
expression referring to such an object shall be evaluated strictly according
to the rules of the abstract machine, as described in 5.1.2.3. Furthermore,
at every sequence point the value last stored in the object shall agree with
that prescribed by the abstract machine, except as modified by the unknown
factors mentioned previously. 114) What constitutes an access to an object
that has volatile-qualified type is implementation-defined.
114) A volatile declaration may be used to describe an object corresponding
to a memory-mapped input/output port or an object accessed by an
asynchronously interrupting function. Actions on objects so declared
shall not be optimized out by an implementation or reordered except as
permitted by the rules for evaluating expressions.
Section 5.1.2.3 "Program execution"
The semantic descriptions in this International Standard describe the
behavior of an abstract machine in which issues of optimization are
irrelevant. Accessing a volatile object, modifying an object, modifying a
file, or calling a function that does any of those operations are all side
effects,11) which are changes in the state of the execution
environment. Evaluation of an expression may produce side effects. At
certain specified points in the execution sequence called sequence points,
all side effects of previous evaluations shall be complete and no side
effects of subsequent evaluations shall have taken place. (A summary of the
sequence points is given in annex C.) In the abstract machine, all
expressions are evaluated as specified by the semantics. An actual
implementation need not evaluate part of an expression if it can deduce that
its value is not used and that no needed side effects are produced
(including any caused by calling a function or accessing a volatile
object). When the processing of the abstract machine is interrupted by
receipt of a signal, only the values of objects as of the previous sequence
point may be relied on. Objects that may be modified between the previous
sequence point and the next sequence point need not have received their
correct values yet. The least requirements on a conforming implementation
are: At sequence points, volatile objects are stable in the sense that
previous accesses are complete and subsequent accesses have not yet
occurred. ... (This is enough)
I believe what this is trying to say is that at some reasonable point (?)
during execution data in the memory hierarchy has to be visible in the actual
memory (where my term "actual memory" is nebulous). This is a good thing. Now
what I also hear is that at some reasonable point during execution processors
need to see the same data, but this often does not mean this data has to be
pushed back through the memory hierarchy rather only the caches may have to be
coherent. This is also a good thing. Hence, there could be cases where one or
the other or both of these concepts are needed in a program. If only cache
coherency is needed, it might be much more efficient to just do that rather
than push the data through the entire memory hierarchy. But I could be wrong.
Does the Java memory-model support both of these concepts? If so, does it do it
independently or combine them. I suggested in my previous message that Java may
not provide the former concept because it desperately tries to hide memory from
the programmer. But I've been wrong before. ;-)
> Try explaining to a class of 2nd or 3rd year students the reasons for when
> it is necessary to qualify a variable with "volatile". You are not going
> to be very successful.
I bet you can get them to understand that you use volatile for
any (scalar or pointer) variable that is accessed across multiple
threads without a lock. And further that you only do such things
when implementing lock-free constructions, only a small handful
of which are useful enough to learn and master. At least my Java
concurrency course students seem to understand that :-)
Now there was a recent movie called "I Robot" and there was a book "I Robot".
Both have the same name but that's where the similarity stops. There is a
language called Java that has a declaration qualifier called "volatile" and
there is a language called C++ that has a declaration qualifier called
"volatile". Both qualifies have the same name but that's where the similarity
stops. The purpose of volatile in C++ is to ensure data gets pushed through the
memory hierarchy. It was never intended to deal with concurrency. (The word
concurrent does not appear in the 554 pages of the C reference manual.) I
noticed this 15 years ago and even tried to tell people this. When C++ volatile
does not work for concurrency, people are upset and confused, but they
shouldn't be because no one ever said it would handle concurrency. So there was
no prior witchcraft with respect to C++ volatile and concurrency.
The witchcraft I was referring to is the paragraphs above that try to formalize
the meaning of volatile with respect to pushing data through the memory
hierarchy. Trying to explain that concept to 2nd or 3rd year students is a
difficult task. Now add to that task your additional explanation about volatile
and concurrency. It could make most instructors break down in tears just
thinking about it. ;-)
More information about the cpp-threads
mailing list