MSDN volatile sample

D

Dave Rahardja


Slightly off topic...

Note that the use of volatile for multithreading on today's
architectures is problematic. Coherency issues, especially on
pipelined, cached, or multi-core systems (which is most of today's
PCs), can become complicated, and is not completely addressed by the
use of volatile.

....and back to C++.

Since the C++ standard does not even recognize the concept of
multithreading, it is much better to rely on OS facilities to perform
interthread synchronization.

....and off again.

Besides, spinlocks are a no-no in my book unless it's in a kernel-mode
device driver that's gated by hardware with very low latency.

-dr
 
S

steve.pagliarulo

Hello everyone,

In the MSDN volatile sample,

http://msdn2.microsoft.com/en-us/library/12a04hfd(VS.80).aspx

I do not understand what is the purpose of the sample. I have tried to
remove the keyword volatile, and the result is the same. :)

Any ideas?

thanks in advance,
George

I would not rely on volatile for anything related to threads. Think of
it as more of a hint to the compiler when it's considering the
variable's scope (especially when optimizing).
 
D

Dave Rahardja

I would not rely on volatile for anything related to threads. Think of
it as more of a hint to the compiler when it's considering the
variable's scope (especially when optimizing).

I don't understand what you mean. volatile has nothing to do with scope
and everything to do with optimization.

Beyond its sequence-point properties, the behavior of volatile
variables is completely implementation-defined, which means that the
effect of the volatile qualifier is not portable in any meaningful,
externally-observable way.

Thus, I wouldn't use it for anything portable, period.

-dr
 
S

spaglia

I don't understand what you mean. volatile has nothing to do with scope
and everything to do with optimization.

Beyond its sequence-point properties, the behavior of volatile
variables is completely implementation-defined, which means that the
effect of the volatile qualifier is not portable in any meaningful,
externally-observable way.

Thus, I wouldn't use it for anything portable, period.

-dr- Hide quoted text -

- Show quoted text -

I believe we are in agreement. My use of scope was targeted to the
optimizer and not the language proper.
-Steve
 
C

Chris Thomasson

[included comp.programming.threads]

George2 said:
Hello everyone,


In the MSDN volatile sample,

http://msdn2.microsoft.com/en-us/library/12a04hfd(VS.80).aspx

I do not understand what is the purpose of the sample. I have tried to
remove the keyword volatile, and the result is the same. :)

Any ideas?

It means that MS compilers for PowerPC (e.g., XBOX), and Itanium (e.g.,
Itanic) based platforms do indeed assign significantly __overbearing!__
memory-barrier functionality to their most "basic" meaning of the volatile
keyword itself; by default! ;^(... Volatile is implementation defined
INDEED!

Basically, they assign heavy acquire-load membar semantics to EVERY _naked_
load, and release-store semantics to EVERY _naked_ store; this could be due
to their relationship with Intel I suppose. Keep in mind that Java does this
as well for programming "simplicity"; IMVHO, all of that crap is MAJOR
overkill and generates unneeded overheads on the memory coherency system in
general. Dumbs down things to a level that makes things ridiculous.

They certainly do NOT have any real need to define volatile such that it has
anything to do with shared-memory threading. IMO, using volatile and
threading in then same sentence is certainly misleading to say the least,
and usually winds up getting people to make erroneous assumptions about
C/C++ compilers...

;^(...
 
J

James Kanze

[included comp.programming.threads]

Maybe. Sometimes.

Without the volatile, the result is undefined behavior.
Depending on the compiler and the processor, it might or it
might not work---changing the optimization level, or running on
a multi-core rather than a single core, make cause the behavior
to be different.

With the volatile, the result is implementation defined
behavior. A compiler may (but is not required to) define some
useful semantics for this case. Most compilers don't, at least
where multi-core systems are concerned. (I don't think that the
code in question will behave reliably on a multi-core system
even when compiled with VC++, at least through version 8.)
It means that MS compilers for PowerPC (e.g., XBOX), and
Itanium (e.g., Itanic) based platforms do indeed assign
significantly __overbearing!__ memory-barrier functionality to
their most "basic" meaning of the volatile keyword itself; by
default! ;^(... Volatile is implementation defined INDEED!
Basically, they assign heavy acquire-load membar semantics to
EVERY _naked_ load, and release-store semantics to EVERY
_naked_ store; this could be due to their relationship with
Intel I suppose. Keep in mind that Java does this as well for
programming "simplicity"; IMVHO, all of that crap is MAJOR
overkill and generates unneeded overheads on the memory
coherency system in general. Dumbs down things to a level that
makes things ridiculous.

I'm not really sure whether the intent of the example is to show
that (VC++ 8 didn't assign those semantics to volatile, at least
not on Intel architectures), or whether it isn't simple another
case of an author not knowing what he is writing about. I've
seen a lot of authors suggest something similar, with the
assumption that it was more or less portable, accross all
compilers.

I might add that a compiler which gives volatile such heavy
semantics doesn't bother me that much, since I never really use
volatile. On a Sparc, as far as I know, there is no way of
synchronizing memory access other than by using a membar
instruction---if volatile is to be used for memory mapped I/O
(it's original rationale), then the compiler must generate the
acquire-load or release-store member instructions.
They certainly do NOT have any real need to define volatile
such that it has anything to do with shared-memory threading.
IMO, using volatile and threading in then same sentence is
certainly misleading to say the least, and usually winds up
getting people to make erroneous assumptions about C/C++
compilers...

Very much agreed. Volatile was really designed for things that
don't behave like memory. Other mechanisms are necessary (and
being proposed) for threading.

I might add that the quality of the MSDN pages is very variable.
I often get the impression that they are written by someone who
doesn't really understand all of the technical issues---they
frequently neglect to give essential information, for example.
(Microsoft is not alone in this: a lot of documentation is
written by technical writers---with the accent on "writers".)
 
M

Michal Nazarewicz

George2 said:
In the MSDN volatile sample,

http://msdn2.microsoft.com/en-us/library/12a04hfd(VS.80).aspx

I do not understand what is the purpose of the sample. I have tried to
remove the keyword volatile, and the result is the same. :)

Any ideas?

volatile means that given variable may change at any time and compiler
have no way of knowing that it may happen (no, it's not the definition
of volatile keyword but it helps understand it). Assume that compiler
knows that Sleep() function will never modify Sentinel -- in this case
a loop

while (Sentinel)
Sleep(0);

might be replaced with

if (Sentinel)
while (1)
Sleep(0);

if there would be no volatile keyword. That's because without volatile
keyword compiler could came to a conclusion that value of Sentinel does
not change in body of the loop so if the condition was true at the
beginning it will be true all the time.

With volatile keyword compiler must check Sentinel's value since it no
longer knows that it's value was not changed (that's basically meaning
of that keyword).
 
J

Joe Greer

volatile means that given variable may change at any time and compiler
have no way of knowing that it may happen (no, it's not the definition
of volatile keyword but it helps understand it). Assume that compiler
knows that Sleep() function will never modify Sentinel -- in this case
a loop

while (Sentinel)
Sleep(0);

might be replaced with

if (Sentinel)
while (1)
Sleep(0);

if there would be no volatile keyword. That's because without volatile
keyword compiler could came to a conclusion that value of Sentinel does
not change in body of the loop so if the condition was true at the
beginning it will be true all the time.

With volatile keyword compiler must check Sentinel's value since it no
longer knows that it's value was not changed (that's basically meaning
of that keyword).

In addition to the above, Microsoft added additional semantics to the
volatile keyword. From their msdn site:

<begin quote>

Microsoft Specific
Objects declared as volatile are not used in certain optimizations
because their values can change at any time. The system always reads the
current value of a volatile object at the point it is requested, even if
a previous instruction asked for a value from the same object. Also, the
value of the object is written immediately on assignment.

Also, when optimizing, the compiler must maintain ordering among
references to volatile objects as well as references to other global
objects. In particular,

A write to a volatile object (volatile write) has Release semantics; a
reference to a global or static object that occurs before a write to a
volatile object in the instruction sequence will occur before that
volatile write in the compiled binary.

A read of a volatile object (volatile read) has Acquire semantics; a
reference to a global or static object that occurs after a read of
volatile memory in the instruction sequence will occur after that
volatile read in the compiled binary.

This allows volatile objects to be used for memory locks and releases in
multithreaded applications.

<end quote>

Hope that helps,
joe
 
C

Chris Thomasson

James Kanze said:
[included comp.programming.threads]

Whoops, forgot to include cpt... Well, we can keep this here.

[...]
It means that MS compilers for PowerPC (e.g., XBOX), and
Itanium (e.g., Itanic) based platforms do indeed assign
significantly __overbearing!__ memory-barrier functionality to
their most "basic" meaning of the volatile keyword itself; by
default! ;^(... Volatile is implementation defined INDEED!
[...]

I'm not really sure whether the intent of the example is to show
that

Well, there is a race-condition if they don't inject the correct barriers.
They are trying to show an example of a producer/consumer pattern such that
the thread which mutates the 'Sentinel' variable is the producer, and the
thread that loads from 'Sentinel' is the consumer. The load needs at least a
#LoadLoad barrier after it, and the store needs at least a #StoreStore
before it. If those barriers are omitted, then the consumer can observe the
store made from the producer _before_ the mutation to the 'CriticalData'
variable is rendered visible. That would be bad...


[...]
Very much agreed. Volatile was really designed for things that
don't behave like memory. Other mechanisms are necessary (and
being proposed) for threading.
I might add that the quality of the MSDN pages is very variable.
I often get the impression that they are written by someone who
doesn't really understand all of the technical issues---they
frequently neglect to give essential information, for example.
(Microsoft is not alone in this: a lot of documentation is
written by technical writers---with the accent on "writers".)

I think your absolutely correct:

http://groups.google.com/group/comp.programming.threads/browse_frm/thread/1b3d65e90d3f5e24

:^0
 
J

James Kanze


[...]
In addition to the above, Microsoft added additional semantics to the
volatile keyword. From their msdn site:
<begin quote>
Microsoft Specific
Objects declared as volatile are not used in certain
optimizations because their values can change at any time. The
system always reads the current value of a volatile object at
the point it is requested, even if a previous instruction
asked for a value from the same object. Also, the value of the
object is written immediately on assignment.
Also, when optimizing, the compiler must maintain ordering
among references to volatile objects as well as references to
other global objects. In particular,
A write to a volatile object (volatile write) has Release
semantics; a reference to a global or static object that
occurs before a write to a volatile object in the instruction
sequence will occur before that volatile write in the compiled
binary.
A read of a volatile object (volatile read) has Acquire
semantics; a reference to a global or static object that
occurs after a read of volatile memory in the instruction
sequence will occur after that volatile read in the compiled
binary.
This allows volatile objects to be used for memory locks and
releases in multithreaded applications.
<end quote>

Interesting. The problem is that unless I've misunderstood
something about the x86 architecture, this description doesn't
correspond to the code generated by VC++ 8. I'm pretty sure
that the achieve these semantics, you need some special code: at
the least, a lock prefix on the accesses to the volatile.
Looking at the generated code, I don't see one.
 

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

Similar Threads

MSDN const_cast sample 2
MSDN for_each sample 2
Struct or class? 10
MSDN template sample 0
safearray 2
manifest file 2
Synchronization and volatile 5
strange grammar about volatile and operator overload 8

Members online

Forum statistics

Threads
473,995
Messages
2,570,226
Members
46,816
Latest member
nipsseyhussle

Latest Threads

Top