int g_counter;
And let's say that this variable is accessed by two different threads.
Here's how the threads might look:
void Thread_One(void)
{
for (;;)
{
if ( !DoSomethingThatTakes15seconds() )
++g_counter;
}
}
void Thread_Two(void)
{
for (;;)
{
if ( DoSomethingThatTakes5seconds() )
--g_counter;
}
}
We need a mutex though. So the second draft would be:
void Thread_One(void)
{
for (;;)
{
if ( !DoSomething() )
{
LockMutex();
++g_counter;
UnlockMutex();
}
}
}
void Thread_Two(void)
{
for (;;)
{
if ( !DoSomething() )
{
LockMutex();
++g_counter;
UnlockMutex();
}
}
}
Finally though, I'd like to clarify one thing:
Do I need to define the g_counter as volatile? I realise that volatile
is intended to be used where the value of a variable can spontaneously
change outside of the normal flow of a program, but I don't know if
this applies to multi-threading.
I'm currently writing cross-platform software which is to be compiled
for different systems such as Windows, Linux, Solaris, Apple Mac.
These different systems have different API's for doing multi-
threading, and maybe each particular API should specify whether global
variables need to be volatile or not. (Or should it be considered
something inherent in the programming language?)
Now the thing is, I'm using the threading library that comes with
wxWidgets. (wxWidgets is a cross-platform library for creating GUI
programs in C++). Within the wxWidgets manual, I can't see anything
about the volatile keyword, so I don't know whether it's needed or
not.
To play it safe, I suppose I could just go and use the volatile
keyword and be done with it. However, this adds a very inconvenient
complication. Let's say I have a global array as follows:
int volatile figures[50];
Inside the code for one of the threads, I might add 7 to every element
of this array:
int const *const pend = figures + (sizeof figures / sizeof
*figures);
for (int *p = figures; figures != pend; ++figures)
*p += 7;
Now the problem here is that this won't compiler, reason being that I
have to tag "volatile" onto all of the pointer definitions. That's a
pain in the ass. (I did it before in a previous C program but it was
quite annoying).
What's the way to go about this? I have some people telling me there's
no need for volatile at all when it comes to multi-threading.
Right.
Cheers & hth.,
- Alf
Virchanza wrote:
> What's the way to go about this? I have some people telling me there's
> no need for volatile at all when it comes to multi-threading.
volatile is neither required nor sufficient for thread safety. You need
other synchronization constructs like your mutex anyway. And calling a
synchronization function includes a full membar. So all of your reads
and writes are executed before the synchronization takes place.
As far as I know e.g. gcc ignores volatile. Some compilers however turn
off optimizations which will not help at all, except that it increases
the chance of a race condition to occur.
But I have seen volatile used at places where strong thread safety is
required. So with C++ function overloading a different, more expensive
read strategy could take place in case of volatile objects.
Marcel
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.
Is it even possible to get an answer to this question, or is it simply
"undefined"?
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.
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.
--
Richard Herring
It was answered definitively here:
<url: http://www.google.com/search?q=alexandrescu+meyers+volatile>
> int g_counter;
No. The system functions ultimately called from LockMutex and
UnlockMutex subsume volatile, and make it unnecessary.
> I realise that volatile is intended to be used where the value
> of a variable can spontaneously change outside of the normal
> flow of a program, but I don't know if this applies to
> multi-threading.
It does, sort of, but... On most systems, it's not sufficient,
and once you've used the necessary synchronization requests (as
above), it's not necessary.
> I'm currently writing cross-platform software which is to be
> compiled for different systems such as Windows, Linux,
> Solaris, Apple Mac. These different systems have different
> API's for doing multi- threading, and maybe each particular
> API should specify whether global variables need to be
> volatile or not. (Or should it be considered something
> inherent in the programming language?)
Linux, and Solaris (and the Mac, I think) use Posix threads;
Posix specifies clearly that volatile is not necessary. Windows
is a bit vaguer, but in practice, the code necessary to
make mutex (or what Windows calls CriticalSection) work will in
fact ensure that volatile is not necessary.
[...]
> What's the way to go about this? I have some people telling me
> there's no need for volatile at all when it comes to
> multi-threading.
That's basically correct: it's absolutely correct for Posix,
it's almost certainly correct for Windows, and it's what the
upcoming version of the C++ standard (which defines threading)
will say as well.
--
James Kanze (GABI Software) email:james...@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
> I'm still not sure whether "a separate thread" qualifies as
> being mysterious enough.
It's mysterious enough, in that sense. The point is that your
synchronization requests have already specified that such
changes can occur, outside the protected region. (In fact,
many compilers, such as Sun CC, g++ and VC++, don't implement
sufficient synchronization for volatile to be usable for much of
anything. Such compilers are arguably broken, but you'll almost
certainly have to use them.)
> Some people are telling me I need volatile. Others are telling
> me I don't need volatile. I don't know who to believe.
> Is it even possible to get an answer to this question, or is
> it simply "undefined"?
You've been given the answer.
Volatile does not guarantee atomic access, nor cache coherency. The
mutex does provide these, so the volatile would be useless here, even
if it did provide these guarantees. If you want a lock-free
implementation, you need to utilize atomic operations. Many OSes
(Windows has the Interlocked functions) and compilers (GCC 4 provides
them as built-ins) provide them. If yours doesn't, you make need to
write your own (e.g., on an Intel, atomics are create by combining
LOCK and the cmpxchg family of instructions). The next version of C++
will have them as part of the standard.
REH
...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" - 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.
> >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.
> 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.
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.
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. To the compiler a value changed by another
thread is just as asynchronous a change as one, say, made by memory-
mapped I/O. And in either case, the "volatile" keyword is needed to
prevent the compiler from caching that variable's value.
Greg
Presumably, you mean that the Meyers & Alexandrescu paper on double-
checked locking:
http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
provides a definitive answer.
And it does. The paper concludes that "volatile" is needed in order to
ensure thread-safety - and in fact is needed more than once:
"Our earlier analysis shows that pInstance needs to be declared
'volatile',
and in fact this point is made in the papers on DCLP. However,
Sherlock Holmes would certainly notice that, in order to ensure
correct instruction order, the Singleton object -itself- must be also
'volatile'. This is not noted in the original DCLP papers, and that’s
an important oversight." [pg 7-8].
Greg
>> 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.
> 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.
>
I agree with Richard here. Once the "other mechanism" is in place,
presumably a mutex involving an OS call, the compiler cannot cache
values across the OS call - unless it first makes sure that the OS is
not using any callbacks previously set, that just might affect our
protected variable. Whether it is volatile or not doesn't matter.
Bo Persson
You might read on... ;-)
> 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. To the compiler a value changed by another
> thread is just as asynchronous a change as one, say, made by memory-
> mapped I/O. And in either case, the "volatile" keyword is needed to
> prevent the compiler from caching that variable's value.
And here I have another person telling me I need volatile.
Honestly I don't know who to believe. Let's say I had a function like:
void SetNullTerminatedArrayToAllFives(int *p)
{
for (;;)
{
if (!*p) return;
*p++ = 5;
}
}
And let's say I have a global null-terminated array:
int my_array[6] = {5,4,3,2,1,0};
And now let's say this will be used between threads, so I make it
volatile:
int volatile my_array[6] = {5,4,3,2,1,0};
Now the problem here is that I can't pass this array to the above
function because I'll get a type mismatch with the "volatile". Is it
necessary to do something like:
int volatile my_volatile_array[6] = {5,4,3,2,1,0};
int (&my_array)[6] = (int (&my_array)[6])my_volatile_array;
I rather create the above reference than litter my code with
"volatile". Or will creating the reference somehow subvert the
volatileness of the object???
> > I'm still not sure whether "a separate thread" qualifies as
> > being mysterious enough.
> It's mysterious enough, in that sense. The point is that your
> synchronization requests have already specified that such
> changes can occur, outside the protected region. (In fact,
> many compilers, such as Sun CC, g++ and VC++, don't implement
> sufficient synchronization for volatile to be usable for much of
> anything. Such compilers are arguably broken, but you'll almost
> certainly have to use them.)
[...]
FWIW, MSVC compilers, versions 8 and above, automatically insert
load-acquire/store-release barriers for volatile loads and stores on certain
architectures (e.g., PowerPC):
_______________________________________________________________
void*
volatile_load(
void** p
) {
void* v = ATOMIC_LOAD(p);
MEMBAR #LoadStore | #LoadLoad;
return v;
}
void*
volatile_store(
void** p,
void* v
) {
MEMBAR #LoadStore | #StoreStore;
ATOMIC_STORE(p, v);
return v;
}
_______________________________________________________________
Please note that this is NOT strong enough for mutual-exclusion such that
you cannot use these memory barrier guarantees to build Petersons Algorithm.
You would need to insert a stronger membar (e.g., MEMBAR #StoreLoad |
#StoreStore) in order to prevent subsequent load from hoisting up above the
previous store in the lock acquire portion of the algorithm. However, it is
strong enough for a DCL algorithm or a producer/consumer example:
_______________________________________________________________
int data = 0;
atomic_word volatile g_flag = 0;
void single_producer() {
data = 1234;
g_flag = 1;
}
void multiple_consumers() {
while (! g_flag) backoff();
assert(data == 1234);
}
_______________________________________________________________
However, these barriers are actually too strong here such that the
#LoadStore restrain is not required for the example... On the SPARC you
could write it as:
_______________________________________________________________
int data = 0;
atomic_word g_flag = 0;
void single_producer() {
data = 1234;
MEMBAR #StoreStore;
g_flag = 1;
}
void multiple_consumers() {
while (! g_flag) backoff();
MEMBAR #LoadLoad;
assert(data == 1234);
}
_______________________________________________________________
Even then, the barriers can be too strong for architectures that support
implicit data-dependant load barriers (e.g., all but the DEC Alpha). You can
write it this way:
_______________________________________________________________
int data = 0;
int* g_flag = 0;
void single_producer() {
data = 1234;
g_flag = &data;
}
void multiple_consumers() {
while (! g_flag) backoff();
assert(*g_flag == 1234);
}
_______________________________________________________________
Normally it is used in device drivers when accessing hardware registers,
which can be updated by the hardware in a way unknown to the compiler.
> 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.
>
> Is it even possible to get an answer to this question, or is it simply
> "undefined"?
The C++ standard does not define the behaviour of threads.
So, the answer to this question is not in the C++ standard.
Threading is usually supported by the underlying operating system.
So, your question is best answered in other news groups.
As others have said, Linux uses posix threads. If the mutex
lock and unlock functions of posix are used, volatile is not needed.
Similarly, when using Windows' native locking, volatile is not needed.
For other operating systems consult the documentation or the appropriate
news group.
As noted by Alf, Greg might want to read on in that paper to the end
where they conclude that volatile as generally implemented is entirely
insufficient as a portable threading primitive in C++. Simply put, the
standard's intent for volatile is mostly memory mapped IO, not
threading, and most compiler writers have implemented this intent,
making volatile not useful as a threading primitive.
> > 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.)
Just a nit, but it has nothing to do with callbacks or any other
particular feature. A compiler cannot cache values accross
certain OS calls because the OS specifications say that it
can't.
> > 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. To
> > the compiler a value changed by another thread is just as
> > asynchronous a change as one, say, made by memory- mapped
> > I/O. And in either case, the "volatile" keyword is needed to
> > prevent the compiler from caching that variable's value.
> And here I have another person telling me I need volatile.
> Honestly I don't know who to believe.
Believe the standard or specification of the system(s) you're
concerned with. Posix says you don't need volatile. So does
Microsoft. For other systems, I don't know; you'll have to
check their documentation.
Note too that a lot of compilers don't really implement volatile
in a way conformant to the intent of the standard. (Formally,
much of the semantics of volatile are implementation defined,
but the intent is clear that each "access" should be externally
visible in some way---a read physically reads whatever is
addressed, and a write physically writes it. On most modern
processors, this requires special instructions, membar, fence,
or at least a lock prefix on an Intel. G++, Sun CC and VC++
don't generate this special code.)
> Let's say I had a function like:
> void SetNullTerminatedArrayToAllFives(int *p)
> {
> for (;;)
> {
> if (!*p) return;
> *p++ = 5;
> }
> }
> And let's say I have a global null-terminated array:
> int my_array[6] = {5,4,3,2,1,0};
> And now let's say this will be used between threads, so I make
> it volatile:
> int volatile my_array[6] = {5,4,3,2,1,0};
Again, at least under Posix or Windows, you don't need to
declare if volatile.
> Now the problem here is that I can't pass this array to the
> above function because I'll get a type mismatch with the
> "volatile".
Yes, because if the array is volatile, the compiler must
generate special (significantly slower) code to access it. (On
a Sun Sparc, if the compiler actually implemented volatile so
that it would guarantee visibilitiy, the code would run about
five times slower.)
> Is it necessary to do something like:
> int volatile my_volatile_array[6] = {5,4,3,2,1,0};
> int (&my_array)[6] = (int (&my_array)[6])my_volatile_array;
That would result in undefined behavior. If you've declared the
array volatile (in practice, I don't think I've ever seen a case
where volatile would be applicable to an array), then you've
told the compiler that all accesses to it must obey special
rules. If you access it through a non-volatile lvalue, the
compiler won't know to apply these special rules, and you'll get
undefined behavior as a result.
> I rather create the above reference than litter my code with
> "volatile". Or will creating the reference somehow subvert the
> volatileness of the object???
It's undefined behavior. Anything might happen. (In practice,
it probably won't change anything, because volatile doesn't
actually do anything significant with most compilers.)
> >http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
> > provides a definitive answer.
> > is not noted in the original DCLP papers, and that’s an
> > important oversight." [pg 7-8].
> You might read on... ;-)
Note that that paper really only addresses one side of the
issue: why you can't avoid the lock. It clearly proves that
volatile is not sufficient. It doesn't address the question as
to whether volatile is necessary or not once you use the thread
synchronization primitives. For that, you need to check the
specifications of the thread synchronization primitives, and
threading in your environment. Both Posix and the Microsoft
documentation say clearly that the thread synchronization
primitives ensure memory synchronization, and so volatile is not
necessary (assuming that your compiler is compliant with the OS,
as well as with the C++ standard)---C++0x will take this path as
well.
> news:524fc5b3-e99e-48af...@v36g2000yqv.googlegroups.com...
> On Jul 27, 2:58 pm, Virchanza <virt...@lavabit.com> wrote:
>
> > > Volatile is intended to be used where a variable's value
> > > can mysteriously change outside of the normal flow of
> > > code. I'm still not sure whether "a separate thread"
> > > qualifies as being mysterious enough.
> > It's mysterious enough, in that sense. The point is that
> > your synchronization requests have already specified that
> > such changes can occur, outside the protected region. (In
> > fact, many compilers, such as Sun CC, g++ and VC++, don't
> > implement sufficient synchronization for volatile to be
> > usable for much of anything. Such compilers are arguably
> > broken, but you'll almost certainly have to use them.)
> [...]
> FWIW, MSVC compilers, versions 8 and above, automatically
> insert load-acquire/store-release barriers for volatile loads
> and stores on certain architectures (e.g., PowerPC):
I knew that Microsoft intended to do this; I hadn't seen it on
the compilers I'd verified. (I forget which version it was, but
it was on a 32 bit Intel.) Microsoft actually proposed this
extension to the meaning of volatile to the standardization
committee, and indicated that they were implementing it in their
compilers. (If I'm not mistaken, it corresponds to the meaning
of volatile in C#.)
Perhaps you should read their reasoning as well as their conclusions?
> Let's say I had a function like:
>
>void SetNullTerminatedArrayToAllFives(int *p)
>{
> for (;;)
> {
> if (!*p) return;
>
> *p++ = 5;
> }
>}
>
>And let's say I have a global null-terminated array:
>
>int my_array[6] = {5,4,3,2,1,0};
>
>And now let's say this will be used between threads, so I make it
>volatile:
>
>int volatile my_array[6] = {5,4,3,2,1,0};
>
>Now the problem here is that I can't pass this array to the above
>function because I'll get a type mismatch with the "volatile".
This is what's called "type safety". The mismatch is there for a reason.
> Is it
>necessary to do something like:
>
>int volatile my_volatile_array[6] = {5,4,3,2,1,0};
>
>int (&my_array)[6] = (int (&my_array)[6])my_volatile_array;
>
>I rather create the above reference than litter my code with
>"volatile". Or will creating the reference somehow subvert the
>volatileness of the object???
Of course it will. Using C-style casts is practically guaranteed to
subvert the type system. If the function isn't declared as taking a
volatile argument, how is the compiler supposed to treat it like one?
You need a synchronisation mechanism, and volatile is not it.
--
Richard Herring