Re: Need to use "volatile" for accessing variables between threads?
On Jul 27, 7:02 pm, Greg Herlihy <gre...@mac.com> wrote:
On Jul 27, 6:37 am, Richard Herring <junk@[127.0.0.1]> wrote:
In message
<9fec04a7-3120-490b-8b9d-524a7bc25...@p23g2000vbl.googlegroups.com>,
Virchanza <virt...@lavabit.com> writes
Volatile is intended to be used where a variable's value
can mysteriously change outside of the normal flow of code.
...which is exactly how changes to a variable's value made on
one thread - appear to another thread.
I'm still not sure whether "a separate thread" qualifies as
being mysterious enough. Some people are telling me I need
volatile. Others are telling me I don't need volatile. I
don't know who to believe.
You do need "volatile"
You might need volatile under some systems (although I don't
know of any). You don't need it under Posix (at least according
to the Posix standard).
- but volatile is by itself is not enough to make your program
thread-safe. You will also need some kind of memory barrier
(or some mutual exclusion mechanism).
Is it even possible to get an answer to this question, or
is it simply "undefined"?
The effect of "volatile" is clearly defined- and clearly
needed for any variable whose value can change asynchronously
with regard to the current execution flow.
The effect of volatile is very loosely defined, intentionally.
The effect of starting a second thread is, in the current C++
standard, undefined behavior, so you can't ask the C++ standard
anything about what is needed. Posix (and presumably Windows
and other OS's) does define this undefined behavior. If the
compiler is Posix compatible (or compatible with the OS it is
running under), then you don't need volatile. If it's not, you
can't use threads with the compiler, period.
FWIW, in practice, none of the compilers I know actually
implement volatile so that it would work, even for its intended
purposes. They do nothing to ensure that modifications "unkown
to the implementation" will be taken into account, and they do
nothing to ensure that a write to a volatile variable will
actually be seen by the hardware.
I'm still not decided.
I think what you're being told is this:
1. volatile doesn't imply atomic access, and therefore it
can't guarantee that another thread won't change a shared
variable while you're half-way through reading it.
True. But the reason why the variable must be declared
"volatile" has nothing to do with assuring exclusive access
or, really, anything to do with threading in particular.
With regards to threading, the only reason possible why a
variable must be declared volatile is that the specifications of
the implementation require it. That's not the case with Posix,
nor as far as I can tell, Windows.
2. Therefore you need some other mechanism to guarantee
thread-safe shared access.
3. Once you have that other mechanism in place, there's no
need to use volatile.
Not so. Declaring a variable "volatile" forces the compiler to
load that variable's value from memory each time that value is
needed.
In theory. (In practice, that's not the case with g++, Sun CC
or VC++.) But that's not required for threading. All that's
required is that any local copies have been purged since the
variable was last modified elsewhere. And pthread_mutex_lock
guarantees that (under Posix).
Otherwise - if there are no apparent write operations to the
variable within a given block of code - then the compiler is
very likely to store the variable's value in a register once
at the beginning of the block; and then use the register-based
value in subsequent operations as that variable's current
value.
Which is fine.
In this case, the value of the variable can change
asynchronously with regard to the current execution flow - and
it does not matter how or why its value may change.
If the value is modified by another thread, you have undefined
behavior, according to Posix. If an object (in the C++ meaning
of the word) is modified by any thread, and accessed in any way
by more than one thread, all accesses to the object must be
synchronized. And of course, the compiler is not allowed to
store the variable's value in a register across synchronization
requests.
To the compiler a value changed by another thread is just as
asynchronous a change as one, say, made by memory-mapped I/O.
Certainly, but since Posix says that such asynchronous requests
are undefined behavior, even with volatile, it doesn't matter.
And in either case, the "volatile" keyword is needed to
prevent the compiler from caching that variable's value.
No. In the first case, Posix defines the access as undefined,
period, with or without volatile. In the second, you're very
deap in implementation defined territory, and you'll have to
follow whatever rules the implementation defines. (The original
purpose of volatile *was* to support such uses, but in practice,
most implementations don't. Thus, for example, the Sparc
architecture manual specifies very clearly that in the case of
memory mapped I/O, all accesses must use a membar instruction to
ensure synchronization, but neither g++ nor Sun CC generate a
membar instruction when accessing a volatile variable.)
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34