Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

volatile keyword usage philosophy (long!)

24 views
Skip to first unread message

Ali Ghorashi

unread,
Jun 11, 2003, 1:52:07 PM6/11/03
to
Hello All,
One of my coworkers and I had an argument over the usage of the 'volatile'
keyword which I was hoping some of you may be able to shed some light on.
First, the K&R book says the following about the volatile keyword:
"The purpose of volatile is to force an implementation to suppress
optimization that could otherwise occur." And then goes on to give a typical
example of a variable being changed by hardware.

At this point, I must add that most of my experience with 'volatile' has
been in the typical case where a variable can change by something outside
the process it's running in.

My co-worker, however, believes that the usage of "volatile int m_x" in the
following example is not only necessary for portability but is good
documentation:

Let's say we have class foo defined as follows:
class Foo{
protected:
volatile int m_x;

friend void ThreadA(..);
friend void ThreadB(..);
};

Assume that MyFoo is a variable that both threads A and B have a pointer to.
Furthermore, assume that "MyFoo.m_x = 0" prior to either thread execution.
The following threads are started at the same time:

void ThreadA(..){
CFoo *pMyFoo=[get a pointer to MyFoo];

while(1){
if(*pMyFoo == 1) break;
}
[Do some work]
}

void ThreadB(..){
CFoo *pMyFoo=[get a pointer to MyFoo];

[Do some work]
*pMyFoo=1;
}

My coworker believes that an "aggressive" optimizer may put the check for
(*pMyFoo == 1) outside the while loop in ThreadA since "optimizers have
functional scope" and will not know that *pMyFoo may be changed somewhere
else. By using the volatile key word, you are guaranteed that something like
that will not happen.

I, on the other hand, believe that it would be wrong for an optimizer to do
such a thing and therefore the usage of the volatile keyword here is not
only "unnecessary" but also misleading.

I would appreciate any input.

-Ali

Alexander Terekhov

unread,
Jun 11, 2003, 2:11:02 PM6/11/03
to

Ali Ghorashi wrote:
[...]

> I would appreciate any input.

http://intel.forums.liveworld.com/thread.jsp?forum=242&thread=6286&message=19622#19622

regards,
alexander.

Jeff Rosenfeld

unread,
Jun 11, 2003, 4:43:34 PM6/11/03
to
Your colleague wins the bet. Your error was was to associate some
operating-system meaning with the word, "process" when a more generic
English meaning should have been applied.

Code re-ordering is a common optimization for a modern compiler to use.
Compilers generally assume single-threaded execution. When multiple threads
have otherwise write access to a data element then the element's value can
change at random from the compiler's perspective. Volatile tells the
compiler that the affected data elements can change in ways that the
compiler cannot predict.

- Jeff.

"Ali Ghorashi" <ali.ghorashi...@lmco.com> wrote in message
news:bc7qdr$dn...@cui1.lmms.lmco.com...

Peter van Merkerk

unread,
Jun 11, 2003, 5:23:35 PM6/11/03
to
[...]

> Let's say we have class foo defined as follows:
> class Foo{
> protected:
> volatile int m_x;
>
> friend void ThreadA(..);
> friend void ThreadB(..);
> };
>
> Assume that MyFoo is a variable that both threads A and B have a pointer
to.
> Furthermore, assume that "MyFoo.m_x = 0" prior to either thread execution.
> The following threads are started at the same time:

[...]


> void ThreadA(..){
> CFoo *pMyFoo=[get a pointer to MyFoo];
>
> while(1){
> if(*pMyFoo == 1) break;
> }
> [Do some work]
> }
>
> void ThreadB(..){
> CFoo *pMyFoo=[get a pointer to MyFoo];
>
> [Do some work]
> *pMyFoo=1;
> }
>
> My coworker believes that an "aggressive" optimizer may put the check for
> (*pMyFoo == 1) outside the while loop in ThreadA since "optimizers have
> functional scope" and will not know that *pMyFoo may be changed somewhere
> else. By using the volatile key word, you are guaranteed that something
like
> that will not happen.

The section 1.9/7 of C++ standard says this about volatile:
"Accessing an object designated by a volatile lvalue (3.10), modifying an
object, calling a library I/O function, or calling a function that does any
of those operations are all side effects, which are changes in the state of
the execution environment. Evaluation of an expression might 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.7)"

Which I believe means that the "aggressive" optimization your coworker is
talking about is not valid according to the C++ standard for volatile
variables.

That being said, ISO C++ is totally agnostic with respect to
multi-threading.
Whatever problem the volatile keyword is supposed to solve, does not resolve
any multi-threading issues. You will have to use platform specific calls for
this, or a library that wraps those calls in a nice package.

<ot>
Even though may get away with the code you posted on your system, platforms
facilities for thread synchronisation should be preferred instead. In your
example ThreadA is burning CPU cycles while waiting for ThreadB to complete.
On a single processor system that could very well mean that ThreadB takes
twice as long to complete because ThreadA is consuming 50% of the available
CPU cycles. With the thread synchronisation methods offered by the platform
ThreadA doesn't have to consume CPU cycles until ThreadB has signalled it
has finished its job.
</ot>

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl


Assaf Lavie

unread,
Jun 11, 2003, 9:26:50 PM6/11/03
to
Ali Ghorashi wrote:

> Hello All,
> One of my coworkers and I had an argument over the usage of the 'volatile'
> keyword which I was hoping some of you may be able to shed some light on.
> First, the K&R book says the following about the volatile keyword:
> "The purpose of volatile is to force an implementation to suppress
> optimization that could otherwise occur." And then goes on to give a typical
> example of a variable being changed by hardware.

...
The following article is just what you need:
http://www.cuj.com/documents/s=7998/cujcexp1902alexandr/alexandr.htm
Andrei Alexandrescu about volatile and thread safety.
Assaf

Andrey Tarasevich

unread,
Jun 11, 2003, 8:40:04 PM6/11/03
to
Ali Ghorashi wrote:
> ...

> Let's say we have class foo defined as follows:
> class Foo{
> protected:
> volatile int m_x;
>
> friend void ThreadA(..);
> friend void ThreadB(..);
> };
>
> Assume that MyFoo is a variable that both threads A and B have a pointer to.
> Furthermore, assume that "MyFoo.m_x = 0" prior to either thread execution.
> The following threads are started at the same time:
>
> void ThreadA(..){
> CFoo *pMyFoo=[get a pointer to MyFoo];
>
> while(1){
> if(*pMyFoo == 1) break;
> }
> [Do some work]
> }
>
> void ThreadB(..){
> CFoo *pMyFoo=[get a pointer to MyFoo];
>
> [Do some work]
> *pMyFoo=1;
> }
> ...

In order to answer your question one first need to now what exactly is meant
under '*pMyFoo == 1' and '*pMyFoo = 1'. I don't see any user-defined
assignment and/or comparison operators in your code, which means that these
expressions are invalid. Is it a typo of some kind? Or you simply forgot to
include the definitions of the above operators?

--
Best regards,
Andrey Tarasevich
Brainbench C and C++ Programming MVP

Alexander Terekhov

unread,
Jun 12, 2003, 5:29:43 AM6/12/03
to

Assaf Lavie wrote:
[...]

> The following article is just what you need:
> http://www.cuj.com/documents/s=7998/cujcexp1902alexandr/alexandr.htm
> Andrei Alexandrescu about volatile and thread safety.

Stop spreading that piece of mixture of "a few interesting thoughts"
and "big chunk of utter silliness", please.

http://groups.google.com/groups?selm=3D7F5630.178962B3%40web.de
http://groups.google.com/groups?selm=3D934ECB.8CD73030%40web.de

regards,
alexander.

P.S. Alexandrescu died yesterday night, BTW. An "accident". Some
critical soft was using C/C++ volatiles in place of proper sync...
and the effect of a race condition killed Andrei (details are still
kept secret but it is known that he died hard with prolonged and
extremely intensive pain, grieve, etc.). RIP (and "holy fuck").

tom_usenet

unread,
Jun 12, 2003, 6:42:07 AM6/12/03
to
On Wed, 11 Jun 2003 11:52:07 -0600, "Ali Ghorashi"
<ali.ghorashi...@lmco.com> wrote:

I think that both you and your coworker are wrong.

volatile is useful for memory that may be modified by something
outside the process (e.g. hardware registers, etc.). Typically, the
volatile variable should be atomically updated by the hardware, or you
may get problems with word-tearing, etc.

For thread synchronization, you should use the multithreading
primatives to synchronize access. Volatile either won't work at all
for what you want (since it doesn't necessarily issue memory
barriers), or it will be a massive pessimization. Instead, you need
either atomic variables and atomic access primitives, or mutexes. In
the code you posted, you should also be using a condition variable and
notifying the waiting thread when it changes.

I'm not an expert, so I may have got something wrong - the best place
to ask about this is comp.programming.threads.

Tom

Alexander Terekhov

unread,
Jun 12, 2003, 7:20:05 AM6/12/03
to

You're not entirely wrong. Originaly, C/C++ volatiles were indead
designed having memory mapped I/O ("registers"/"ports") in mind. At
that time hardware was rather simplistic and didn't do any reordering
in either "ordinal" or "I/O" space. Modern hardware COULD reorder
memory accesses in ALL spaces. So, you basically need almost the same
reordering constrains (see the links below) for portable device driver
programming as for threading. The situation is actually kinda more
complicated because for device drivers you'd need to "control" BOTH
spaces -- e.g. if you publish a bunch of structure addresses and those
structure meant to be read/write by some device driver you really need
to ensure "cross"-space ordering. Unfortunately, the upcoming <iohw.h>
and <hardware> still lacks facilities to do that... unless they really
want to impose "total ordering" if you use any IO read/write calls.
Later, volatiles were kinda {re-}used for setjmp/longjmp stuff in order
to spill the locals to memory (and to reload them after the jump).
Finally, volatiles are also needed for static sig_atomic_t's. Both
these uses of volatiles are purely "single-threaded". Ideally, we
should get rid completely of setjmp/longjmp (ISO C should adopt C++
exceptions.. but after they will be repaired, of course) and also
asynchronous signals (threads shall replace them). Given the upcoming
<iohw.h> and <hardware>, C/C++ volatiles could then be deprecated as
well. Now, back to threading and C++... here's some C++ code for
"curious" folks who can "speak C++":

http://www.terekhov.de/pthread_refcount_t/experimental/refcount.cpp

Some wording about msync "semantics" can be found here:

http://www.google.com/groups?selm=3EE0CA46.593F938B%40web.de
(Subject: Re: Asynchronous queue without synchronization primitives)

Reference counting operation are described here:

http://www.terekhov.de/pthread_refcount_t/draft-edits.txt

Comments are quite welcome. TIA.

regards,
alexander.

P.S. Tom, don't miss the use of enums for overloading. ;-)

tom_usenet

unread,
Jun 12, 2003, 9:41:57 AM6/12/03
to
On Thu, 12 Jun 2003 13:20:05 +0200, Alexander Terekhov
<tere...@web.de> wrote:

>P.S. Tom, don't miss the use of enums for overloading. ;-)

Ahh, but that's in member functions, so that's ok! I only frown about
it in namespace scope functions, where it could potentially cause the
wrong overload to be called (e.g. an int overload instead of your enum
overload), or at least cause an ambiguity. ;o)

Tom

Ali Ghorashi

unread,
Jun 12, 2003, 11:14:14 AM6/12/03
to
OK,
I think some of you took my question the wrong way. I must mention that my
example had a typo in it: "CFoo" and "Foo class" are the same thing.
My question here is really not about thread synchronization but about the
language keyword 'volatile'. My question is basically this:

In my simple example, if I do not use "volatile", is it possible for a "bug
free" C++ compiler to perform loop optimization on the "while(1)" loop in
ThreadA? And by loop optimization I mean putting the statements with
constant values outside the loop.

Regards,
-Ali

"Ali Ghorashi" <ali.ghorashi...@lmco.com> wrote in message
news:bc7qdr$dn...@cui1.lmms.lmco.com...

Karl Heinz Buchegger

unread,
Jun 12, 2003, 11:41:57 AM6/12/03
to

Ali Ghorashi wrote:
>
> OK,
> I think some of you took my question the wrong way. I must mention that my
> example had a typo in it: "CFoo" and "Foo class" are the same thing.
> My question here is really not about thread synchronization but about the
> language keyword 'volatile'. My question is basically this:
>
> In my simple example, if I do not use "volatile", is it possible for a "bug
> free" C++ compiler to perform loop optimization on the "while(1)" loop in
> ThreadA? And by loop optimization I mean putting the statements with
> constant values outside the loop.

Sure. Thats one basic optimization which is done by compilers. If something
is constant and the compiler can proove that it is constant then there
is no point in calculating it over and over again.

In your example:

--
Karl Heinz Buchegger
kbuc...@gascad.at

Karl Heinz Buchegger

unread,
Jun 12, 2003, 11:45:12 AM6/12/03
to

Sorry hit send by accident.


Karl Heinz Buchegger wrote:
>
> Ali Ghorashi wrote:
> >
> > OK,
> > I think some of you took my question the wrong way. I must mention that my
> > example had a typo in it: "CFoo" and "Foo class" are the same thing.
> > My question here is really not about thread synchronization but about the
> > language keyword 'volatile'. My question is basically this:
> >
> > In my simple example, if I do not use "volatile", is it possible for a "bug
> > free" C++ compiler to perform loop optimization on the "while(1)" loop in
> > ThreadA? And by loop optimization I mean putting the statements with
> > constant values outside the loop.
>
> Sure. Thats one basic optimization which is done by compilers. If something
> is constant and the compiler can proove that it is constant then there

Should read:
If there is an expression inside a loop and the compiler can proove that it
is constant then there

> is no point in calculating it over and over again.
>
> In your example:

CFoo *pMyFoo=[get a pointer to MyFoo];

while(1){
if(*pMyFoo == 1) break;
}

the compiler deduces that there is no way that either the pointer
nor the object the pointer points to can change.

tom_usenet

unread,
Jun 12, 2003, 11:56:34 AM6/12/03
to
On Thu, 12 Jun 2003 09:14:14 -0600, "Ali Ghorashi"
<ali.ghorashi...@lmco.com> wrote:

>OK,
>I think some of you took my question the wrong way. I must mention that my
>example had a typo in it: "CFoo" and "Foo class" are the same thing.
>My question here is really not about thread synchronization but about the
>language keyword 'volatile'. My question is basically this:
>
>In my simple example, if I do not use "volatile", is it possible for a "bug
>free" C++ compiler to perform loop optimization on the "while(1)" loop in
>ThreadA? And by loop optimization I mean putting the statements with
>constant values outside the loop.

The effect of C++ code is described in terms of:

a) reads from and writes to volatile variables.
b) output statements.

Providing a program produces the expected output and sequence of reads
and writes to volatile variables, it can do what it wants. e.g.
something like:

int main()
{
int i;
for (i = 0; i < 1000000; ++i)
{
}
std::cout << i << '\n';
}

can easily be optimized to:

int main()
{
std::cout << 100000 << '\n';
}

However,

int main()
{
int j;
volatile int& i = j;
for (i = 0; i < 1000000; ++i)
{
}
std::cout << i << '\n';
}

cannot have the loop optimized.

Tom

Assaf Lavie

unread,
Jun 12, 2003, 4:46:29 PM6/12/03
to
Alexander Terekhov wrote:
> Assaf Lavie wrote:
> [...]
>
>>The following article is just what you need:
>>http://www.cuj.com/documents/s=7998/cujcexp1902alexandr/alexandr.htm
>>Andrei Alexandrescu about volatile and thread safety.
>
>
> Stop spreading that piece of mixture of "a few interesting thoughts"
> and "big chunk of utter silliness", please.
>
> http://groups.google.com/groups?selm=3D7F5630.178962B3%40web.de
> http://groups.google.com/groups?selm=3D934ECB.8CD73030%40web.de
Those two posts contain no material objections to the ideas presented by
alexandrescu. It's just you saying "that's wrong" about ten times, not
very helpfull.
If you care to explain yourself better I'd very much like to hear what's
so wrong with that article.

Thanks.

Alexander Terekhov

unread,
Jun 12, 2003, 4:18:25 PM6/12/03
to

Assaf Lavie wrote:
[...]

> If you care to explain yourself better I'd very much like to hear what's
> so wrong with that article.

http://google.com/groups?selm=3A66E4A1.54EE37AD%40compaq.com
http://google.com/groups?selm=QJZo9.17%24X93.717939%40news.cpqcorp.net

regards,
alexander.

0 new messages