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

When to use the 'volatile' keyword ?

4 views
Skip to first unread message

pbi

unread,
Nov 4, 2002, 2:23:40 PM11/4/02
to
Should I use the 'volatile' type qualifier when declaraing variable
which will be accessed by multithread?
For example:

int flag=1;

fun1()
{
while(flag)
{
}
}

fun2()
{
flag=0;
}

fun1 and fun2 are executed in different threads. If I don't use
volatile to modify the variable flag's definition, compiler might do
some optimizations that
cause the loop in fun1 infinite. So I think I should modify the first
line to
volatile int flag=1;
But how about if flag is not a primitive type variable? If its type is
a class, or if it's a member of a class, should I use the volatile
keyword?

thanks

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Ron

unread,
Nov 5, 2002, 11:19:29 AM11/5/02
to
> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread?
> For example:
>
> int flag=1;
>
> fun1()
> {
> while(flag)
> {
> }
> }
>
> fun2()
> {
> flag=0;
> }
>
> fun1 and fun2 are executed in different threads. If I don't use
> volatile to modify the variable flag's definition, compiler might do
> some optimizations that cause the loop in fun1 infinite. So I think I should
> modify the first line to
>
> volatile int flag=1;

I *know* that my response will restart a long-simmering debate over
the adequacy of "volatile", the merits of pthreads, and the nature of
the universe, but I can't resist.

The C++ spec does not mention threads. However, as I read s.1.9(6-7),
making your variable "volatile" should guarantee that its current
value is always visible to multiple threads. You must, of course, also
use an appropriate synchronization mechanism (such as a mutex) to
insure that multiple threads view (and operate) upon the variable in a
consistent manner.

Or, you could use Posix pthreads, which handle both synchronization
and interthread visibility.

-- Ron

Shannon Barber

unread,
Nov 5, 2002, 1:36:35 PM11/5/02
to
p...@21cn.com (pbi) wrote in message news:<b9a051e6.02110...@posting.google.com>...

> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread?
> For example:
>
> int flag=1;
>
> fun1()
> {
> while(flag)
> {
> }
> }
>
> fun2()
> {
> flag=0;
> }
>
> fun1 and fun2 are executed in different threads. If I don't use
> volatile to modify the variable flag's definition, compiler might do
> some optimizations that
> cause the loop in fun1 infinite. So I think I should modify the first
> line to
> volatile int flag=1;

This is the C textbook example use of volatile - it's not a generally
recommended practice, but it demonstrates the issue volatile
addresses.

> But how about if flag is not a primitive type variable? If its type is
> a class, or if it's a member of a class, should I use the volatile
> keyword?
>

For classes volatile behaves much like const; you can only invoke
methods tagged (what's the official term for the cvq keyword after a
method defintion?) with volatile. You can also cast away the
volatile'ness with const_cast (say, after acquiring mutex).


struct Test
{
void foo() volatile {}
void manchu(){}
};

int main()
{
volatile Test test;

test.foo(); //no problem
test.manchu(); //fails to compile

Gerhard Menzl

unread,
Nov 5, 2002, 1:43:02 PM11/5/02
to
pbi wrote:

> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread?

No. Declaring a variable volatile does not make it thread-safe. You need
to use proper thread synchronization mechanisms, such as mutexes or
critical sections, depending on your platform.

Gerhard Menzl

Thomas Richter

unread,
Nov 5, 2002, 1:45:19 PM11/5/02
to
Hi,

> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread?

In general, you need to provide some access control mechanism. At least
AFAIK there is no guaranteed "atomic" operation you could really rely
upon in C++: The thread scheduler could just rescedule the threads
"under your feet" with the variable half-changed, whatever "half" means
in the context of your working environment. What you want to use here is a
concept like "mutexes". These aren't part of the C++ specifications,
but should be available within the thread library you're using. Lock
the mutex before you read or write-access the flag within any mutex,
unlock it if you're done with it. To ensure that the compiler really
updates(!) the variable in question and not a locally cached copy, declare
them as volatile.

> fun1 and fun2 are executed in different threads. If I don't use
> volatile to modify the variable flag's definition, compiler might do
> some optimizations that
> cause the loop in fun1 infinite. So I think I should modify the first
> line to volatile int flag=1;

That might be not enough, dependent on the architecture you work on.
I would expect that modification of an int is an atomic operation,
but this need not to be so.

So long,
Thomas

Larry Brasfield

unread,
Nov 5, 2002, 2:01:10 PM11/5/02
to
In article <b9a051e6.02110...@posting.google.com>,
pbi (p...@21cn.com) says...

> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread?

Yes, in general. The volatile qualifier
tells the compiler that actual reads and
writes to the variable are the intended
(and defined) effect of the code rather
than the "as if" behavior that could be
assumed by an optimizer.

> For example:
>
> int flag=1;
>
> fun1()
> {
> while(flag)
> {
> }
> }
>
> fun2()
> {
> flag=0;
> }
>
> fun1 and fun2 are executed in different threads. If I don't use
> volatile to modify the variable flag's definition, compiler might do
> some optimizations that cause the loop in fun1 infinite. So I think
> I should modify the first line to
> volatile int flag=1;

Yes, of course.

> But how about if flag is not a primitive type variable? If its type is
> a class, or if it's a member of a class, should I use the volatile
> keyword?

Yes, for the same reasons. Additionally,
if you are accessing an aggregate object
from multiple threads, you will probably
need to provide for exclusive access so
that the class invariants that ordinarily
outside of member function calls are not
left invalid when a thread switch occurs
during a member call.

As a side note, the nearly inevitable side
effect of calling the functions necessary
to effect exclusion is to flush any pending
writes to, and drop any assumptions about,
the objects you might want to make volatile.

--
-Larry Brasfield
(address munged, s/sn/h/ to reply)

Michel de Becdelièvre

unread,
Nov 5, 2002, 3:00:58 PM11/5/02
to

>
> fun1 and fun2 are executed in different threads. If I don't use
> volatile to modify the variable flag's definition, compiler might do
> some optimizations that
> cause the loop in fun1 infinite. So I think I should modify the first
> line to
> volatile int flag=1;
> But how about if flag is not a primitive type variable? If its type is
> a class, or if it's a member of a class, should I use the volatile
> keyword?
>
Volatile more or less means "no optimization at all", it does not mean
"no race conditions" which is the real problem of threads.
Generally, you need some sort of mutex. In your very simple test case
however it will probably work.

Maciej Sobczak

unread,
Nov 5, 2002, 3:04:50 PM11/5/02
to
Hi,

"pbi" <p...@21cn.com> wrote in message
news:b9a051e6.02110...@posting.google.com...


> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread?

This can generate a hot and interesting thread (pun intended).

In general, you should take into account *ALL* possible ways the shared
object can be modified and analyse their impact on both writer and reader.
On single-processor system, I do not see any problem with int type, since a
thread is unlikely to be preempted in the middle of modifying int value. Or
is it?

Let's suppose that the writer thread *can* be preempted in the middle of
modification. It can happen that the reader thread will read the value that
is malformed. I'm not talking about a "strange" value, but about a trap
value that is not a valid integer. No mercy then.

On simple platforms (you are likely to have one on your desk), where at
least one of these holds:
- there are no trap values for int
- the modification of int cannot be preempted
(Intel boxes give both guarantees)
There is nothing to worry about.
After writer modifies the value, sooner or later the reader will be able to
read it and in your code only zero and non-zero values are distinguished, so
even intermediate values are out of concern.

With more complex types you can have *exactly* the same problems, but they
scale up and show their ugly heads. The writer can be preempted in the
middle of its operation, rendering the value of the object invalid. Use some
synchronization (mutex?) so that the reader keeps its hands off the object
until the writer finishes.

And my follow-up question:
Is there any reason to qualify objects of complex classes as "volatile" if
they are supposed to be shared between threads? (forget for the moment that
it's off-the-group)

Cheers,

--
Maciej Sobczak
http://www.maciejsobczak.com/

James Kanze

unread,
Nov 5, 2002, 4:51:22 PM11/5/02
to
p...@21cn.com (pbi) wrote in message
news:<b9a051e6.02110...@posting.google.com>...
> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread? For example:

> int flag=1;

> fun1()
> {
> while(flag)
> {
> }
> }

> fun2()
> {
> flag=0;
> }

> fun1 and fun2 are executed in different threads. If I don't use
> volatile to modify the variable flag's definition, compiler might do
> some optimizations that cause the loop in fun1 infinite.

Even if you use volatile, the hardware might do some optimizations which
cause the loop in fun1 to be infinite. For various reasons, volatile
doesn't really buy you that much.

If you are using Posix threads, the rules are quite clear. As soon as
any thread may modify the value, all accesses, read or write, must be
protected. The routines involved in the protection are responsible
(according to the Posix standard) for synchronizing the memory (which
typically involves executing some special machine instructions).

> So I think I should modify the first line to volatile int flag=1; But
> how about if flag is not a primitive type variable?

Then all bets are off.

> If its type is a class, or if it's a member of a class, should I use
> the volatile keyword?

If you're using threads, forget about volatile.

--
James Kanze mailto:jka...@caicheuvreux.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung

Alexander Terekhov

unread,
Nov 5, 2002, 5:04:04 PM11/5/02
to

Shannon Barber wrote:
>
> p...@21cn.com (pbi) wrote in message news:<b9a051e6.02110...@posting.google.com>...
> > Should I use the 'volatile' type qualifier when declaraing variable
> > which will be accessed by multithread?
> > For example:
> >
> > int flag=1;
> >
> > fun1()
> > {
> > while(flag)
> > {
> > }
> > }
> >
> > fun2()
> > {
> > flag=0;
> > }
> >
> > fun1 and fun2 are executed in different threads. If I don't use
> > volatile to modify the variable flag's definition, compiler might do
> > some optimizations that
> > cause the loop in fun1 infinite. So I think I should modify the first
> > line to
> > volatile int flag=1;
>
> This is the C textbook example use of volatile - it's not a generally
> recommended practice, but it demonstrates the issue volatile
> addresses.

C/C++ volatile DOESN'T address any issues related to THREADING.

> > But how about if flag is not a primitive type variable? If its type is
> > a class, or if it's a member of a class, should I use the volatile
> > keyword?
> >
> For classes volatile behaves much like const; you can only invoke
> methods tagged (what's the official term for the cvq keyword after a
> method defintion?) with volatile. You can also cast away the
> volatile'ness with const_cast (say, after acquiring mutex).

Mama mia. That's UNDEFINED BEHAVIOR [if you access it]. End of story.

Well, more on this:

http://groups.google.com/groups?threadm=ajaqne%24n9u%241%40glue.ucr.edu
(comp.std.c, Subject: concurrency-induced memory-access anomalies)

http://groups.google.com/groups?threadm=A35E63.5050200%40xx.xxx
(c.p.t., Subject: Talking about volatile and threads synchronization...)

http://groups.google.com/groups?selm=BFF494.5FB11101%40web.de
(comp.std.c, Subject: Re: Volatile automatic variables and setjmp)

regards,
alexander.

Carlos Moreno

unread,
Nov 5, 2002, 5:05:44 PM11/5/02
to
Ron wrote:
>
> I *know* that my response will restart a long-simmering debate over
> the adequacy of "volatile", the merits of pthreads, and the nature of
> the universe

For an interesting discussion about the nature of the universe,
you (I mean, the OP) can check the thread I started a few weeks
ago in the newsgroup comp.programming.threads, with subject


"Talking about volatile and threads synchronization."

After 65 articles, I think the conclusion was that depending
on the threads library that you use, you *may* need to use
volatile *in addition* to proper synchronization mechanisms.

With POSIX threads, as Ron indicated, there is absolutely no
need to use volatile (trust me: read the 65 articles in that
thread :-)).

Volatile in general avoids optimizations concerning skipping
a read to a variable because the compiler assumes its value
by inspecting the surrounding code. This is particularly
useful when reading memory-mapped hardware registers, for
which the contents may change in a way completely beyond
the control or the awareness of the executing program. But
for threads (at least with POSIX threads), apparently is
not that useful, since you *must* use synchronization
techniques anyway (otherwise accesses to even an int could
end up conflicting and leaving the int in an inconsistent
state, if the timing is right -- I mean profoundly wrong :-)),
and synchronization techniques save you also from the problem
that volatile saves you from...

Anyway, go to http://groups.google.com, and then type the
subject I indicated above (make sure you enclose it in
double-quotes) for more details.

HTH,

Carlos
--

Jerry Coffin

unread,
Nov 6, 2002, 2:45:37 PM11/6/02
to
In article <de001473.02110...@posting.google.com>,
shannon...@myrealbox.com says...

[ ... ]

> For classes volatile behaves much like const; you can only invoke
> methods tagged (what's the official term for the cvq keyword after a
> method defintion?)

const and volatile are qualifiers, so I guess the function would be
"qualified".

> with volatile. You can also cast away the
> volatile'ness with const_cast (say, after acquiring mutex).

Yes -- from a pedantic viewpoint, it should probably have been named
qualification_cast (or maybe just qual_cast) instead of const_cast,
but const is _so_ much more common that it's probably better the way
it is.

--
Later,
Jerry.

The universe is a figment of its own imagination.

Garry Lancaster

unread,
Nov 6, 2002, 2:53:28 PM11/6/02
to
pbi:

> Should I use the 'volatile' type qualifier when declaraing variable
> which will be accessed by multithread?

The C++ standard does not deal with multiple threads of
execution. So, the answer is "it depends on your threading
environment".

POSIX threads (pthreads) rules are that the volatile qualifier
is neither necessary nor sufficient for safe multi-thread
access: in fact its main effect is to act as a pessimization
inhibiting many harmless compiler optimizations.

Windows threading rules are, as far as I know, not spelled
out anywhere explicitly so it depends on the hardware you
are running on. Win32 on x86 is a more permissive threading
environment than pthreads (i.e. you can get away with more),
but Alpha (yes, Windows was ported to the Alpha) is fairly
similar to the pthreads model and I'm guessing Win64
hardware will be more Alpha-like in this respect. So, I would
still generally recommend sticking with the pthreads memory
visibility model. It is quite close to the minimum that would
actually work, so you will if anything be erring on the side of
caution.

In summary, your example as written, either with or without
the volatile qualification, is a very non-portable way of doing
things: there are a lot of platforms where it will not work.
If you protect all accesses to the flag with a mutex (a.k.a
CRITICAL_SECTION on Windows) you will have a very
portable solution (at least conceptually: in practice the syntax
for initializing, locking, unlocking and destroying a mutex
differs between threading systems although Boost.Threads
abstracts away these differences for all systems it supports)
Their are likely other solutions that sit somewhere in between.

For more information...

Boost.Threads is a library at www.boost.org.

The best book on pthreads is probably David Butenhof's one.
Even if you don't use pthreads, it is conceptually very clear
about how threading works.

Windows threading documentation is at msdn.microsoft.com.

Also see the comp.programming.threads FAQ. If you are still stuck,
you will probably find more threading people on that newsgroup
than this one.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

Ron

unread,
Nov 7, 2002, 11:51:47 AM11/7/02
to
> > Should I use the 'volatile' type qualifier when declaraing variable
> > which will be accessed by multithread? For example:
>
> > int flag=1;
>
> > fun1()
> > {
> > while(flag)
> > {
> > }
> > }
>
> > fun2()
> > {
> > flag=0;
> > }
>
> > fun1 and fun2 are executed in different threads. If I don't use
> > volatile to modify the variable flag's definition, compiler might do
> > some optimizations that cause the loop in fun1 infinite.
>
> Even if you use volatile, the hardware might do some optimizations
which
> cause the loop in fun1 to be infinite....

This would occur only on processors that support loosely-ordered
memory regions, and only if the compiler, linker, and operating system
happened to place the variable within such a region. Since such
regions do not guarantee that the following runs without an assertion:

int i;
i = 5;
i = 7;
assert (i == 7);

any compiler/linker/os that automatically placed the original poster's
variable into such a region would be broken.

-- Ron

Garry Lancaster

unread,
Nov 8, 2002, 1:27:36 PM11/8/02
to
Ron wrote:
> > > Should I use the 'volatile' type qualifier when declaraing
variable
> > > which will be accessed by multithread? For example:
> >
> > > int flag=1;
> >
> > > fun1()
> > > {
> > > while(flag)
> > > {
> > > }
> > > }
> >
> > > fun2()
> > > {
> > > flag=0;
> > > }
> >
> > > fun1 and fun2 are executed in different threads. If I don't use
> > > volatile to modify the variable flag's definition, compiler might
do
> > > some optimizations that cause the loop in fun1 infinite.

James Kanze replied:


> > Even if you use volatile, the hardware might do some
> > optimizations which cause the loop in fun1 to be infinite....

Ron responded doubtfully:


> This would occur only on processors that support loosely-ordered
> memory regions, and only if the compiler, linker, and operating system
> happened to place the variable within such a region. Since such
> regions do not guarantee that the following runs without an assertion:
>
> int i;
> i = 5;
> i = 7;
> assert (i == 7);
>
> any compiler/linker/os that automatically placed the original poster's
> variable into such a region would be broken.

No, James is right. The visibility and ordering rules
for same-thread and different-thread variable accesses
are, on some common threading systems such as
POSIX, permitted to be very, very different.

An abstract machine model I find very helpful to
understanding all this is a machine with a single
main memory but a main-memory-sized cache for
each thread.

Each thread starts with a perfect copy of main
memory in its cache, but need not ever access
main memory again except when explicit thread
synchronization is employed i.e. each thread can
work in isolation just reading and writing to its own
cache. (Those familiar with the Java memory model
will undoubtedly note that it is similar.)

Under this model (which is POSIX compliant by
the way) it's easy to see why, in the absence of
explicit synchonization, one thread need not
ever see a value written by another.

Hope this helps.

Kind regards

Garry Lancaster
Codemill Ltd
Visit our web site at http://www.codemill.net

0 new messages