Re: SEH and standard C++ exceptions by Doug
Doug
Fri Feb 06 12:35:59 CST 2004
ak wrote:
>when marking a variable volatile one indicates for
>the compiler that maybe another thread would
>update the variable in question so therefor do not
>optimize away the variable.
>
>the optimizer could otherwise sometimes drop the
>variable altogether.
So many misconceptions exist concerning the use of volatile with threads
that it's probably best not to mention them in the same breath. :) In
multithreaded programming, synchronization is far more important than
volatile, which is neither sufficient nor necessary when all access to a
variable is protected by a mutex. When you faithfully observe your locking
protocol to access a variable, declaring that variable volatile merely slows
down your code, and for class types, greatly interferes with use of the
object, because no one (A.A. excepted :) declares member functions volatile.
In addition, if your class type "X" contains a char* member "p" which points
to a buffer you would like to be volatile, declaring an X object volatile
doesn't apply to the buffer data at all, but just to p. So it's hard to
imagine a valid use of volatile on objects of class type.
What about fundamental types like int? I can think of four valid uses for
volatile, all more or less related to the idea that volatile suppresses
optimizations and forces the compiler to go to memory for each read and
write to a volatile object.
1. On amenable hardware like x86, this idiom can work, and it requires
volatile to prevent the compiler from caching x in a register in the loop:
// The variable x is accessible to multiple threads, one or more of
// which change it and indirectly stop the loop below, which is
// executing in another thread. Note that x must always be accessed
// atomically for this sort of thing to work in general.
volatile bool x = true;
while (x)
whatever;
// Assuming everyone observes the locking protocol, this approach
// would work on all hardware, even weird architectures like Sparc
// and others which require memory barriers:
bool x = true; // As above, just non-volatile
for (;;)
{
lock(mx);
bool y = x;
unlock(mx);
if (!y)
break;
whatever;
}
2. You need volatile to avoid undefined behavior in certain signal handler
and setjmp/longjmp scenarios.
3. You can use volatile, say, to declare a pointer to a volatile int, which
represents a memory location updated at the interrupt level, something you
can't synchronize with, and which is outside the compiler's knowledge of the
program.
4. You can use volatile to prevent the compiler from optimizing away
operations which, as far as the compiler is concerned, seem to have no
purpose, because it can't see that the results are used or that the side
effects of computing the results are important. (This one fits your division
by zero example.)
--
Doug Harrison
Microsoft MVP - Visual C++