Why Does Volatile Exist

Why does volatile exist?

volatile is needed if you are reading from a spot in memory that, say, a completely separate process/device/whatever may write to.

I used to work with dual-port ram in a multiprocessor system in straight C. We used a hardware managed 16 bit value as a semaphore to know when the other guy was done. Essentially we did this:

void waitForSemaphore()
{
volatile uint16_t* semPtr = WELL_KNOWN_SEM_ADDR;/*well known address to my semaphore*/
while ((*semPtr) != IS_OK_FOR_ME_TO_PROCEED);
}

Without volatile, the optimizer sees the loop as useless (The guy never sets the value! He's nuts, get rid of that code!) and my code would proceed without having acquired the semaphore, causing problems later on.

C++ Why does the const volatile type qualifier exist?

If you define

const some_type x = some_value;

that means you can't modify the value of x. In the absence of volatile, the compiler can replace a reference to x by some_value.

If you define

const volatile some_type x = some_value;

then you still can't modify x (at least not by using the name x), but the compiler can no longer assume that its value cannot change. Any reference to the value of x must actually load its value from memory; it can't assume that it will always retain its initial value.

For example, there might be some compiler-specific attribute that associates x with some device. The name x provides a read-only view of the object; the volatile inhibits certain optimizations.

Why do we use volatile keyword?

Consider this code,

int some_int = 100;

while(some_int == 100)
{
//your code
}

When this program gets compiled, the compiler may optimize this code, if it finds that the program never ever makes any attempt to change the value of some_int, so it may be tempted to optimize the while loop by changing it from while(some_int == 100) to something which is equivalent to while(true) so that the execution could be fast (since the condition in while loop appears to be true always). (if the compiler doesn't optimize it, then it has to fetch the value of some_int and compare it with 100, in each iteration which obviously is a little bit slow.)

However, sometimes, optimization (of some parts of your program) may be undesirable, because it may be that someone else is changing the value of some_int from outside the program which compiler is not aware of, since it can't see it; but it's how you've designed it. In that case, compiler's optimization would not produce the desired result!

So, to ensure the desired result, you need to somehow stop the compiler from optimizing the while loop. That is where the volatile keyword plays its role. All you need to do is this,

volatile int some_int = 100; //note the 'volatile' qualifier now!

In other words, I would explain this as follows:

volatile tells the compiler that,

"Hey compiler, I'm volatile and, you
know, I can be changed by some XYZ
that you're not even aware of. That
XYZ could be anything. Maybe some
alien outside this planet called
program. Maybe some lightning, some
form of interrupt, volcanoes, etc can
mutate me. Maybe. You never know who
is going to change me! So O you
ignorant, stop playing an all-knowing
god, and don't dare touch the code
where I'm present. Okay?"

Well, that is how volatile prevents the compiler from optimizing code. Now search the web to see some sample examples.


Quoting from the C++ Standard ($7.1.5.1/8)

[..] volatile is a hint to the
implementation to avoid aggressive
optimization involving the object

because the value of the object might
be changed by means undetectable by an
implementation.[...]

Related topic:

Does making a struct volatile make all its members volatile?

Understanding volatile keyword in c++

The volatile keyword in C++ was inherited it from C, where it was intended as a general catch-all to indicate places where a compiler should allow for the possibility that reading or writing an object might have side-effects it doesn't know about. Because the kinds of side-effects that could be induced would vary among different platforms, the Standard leaves the question of what allowances to make up to compiler writers' judgments as to how they should best serve their customers.

Microsoft's compilers for the 8088/8086 and later x86 have for decades been designed to support the practice of using volatile objects to build a mutex which guards "ordinary" objects. As a simple example: if thread 1 does something like:

ordinaryObject = 23;
volatileFlag = 1;
while(volatileFlag)
doOtherStuffWhileWaiting();
useValue(ordinaryObject);

and thread 2 periodically does something like:

if (volatileFlag)
{
ordinaryObject++;
volatileFlag=0;
}

then the accesses to volatileFlag would serve as a warning to Microsoft's compilers that they should refrain from making assumptions about how any preceding actions on any objects would interact with later actions. This pattern has been followed with the volatile qualifiers in other languages like C#.

Unfortunately, neither clang nor gcc includes any option to treat volatile in such a fashion, opting instead to require that programmers use compiler-specific intrinsics to yield the same semantics that Microsoft could achieve using only the Standard keyword volatile that was intended to be suitable for such purposes [according to the authors of the Standard, "A volatile object is also an appropriate model for a variable shared among multiple processes."--see http://www.open-std.org/jtc1/sc22/wg14/www/C99RationaleV5.10.pdf p. 76 ll. 25-26]

Everything is volatile

In C++, volatile has nothing to do with thread safety. You cannot rely on it to avoid data races. Its purpose is to force synchronised accesses to a variable (from a single thread, or threads that use some other mechanism to synchronise with each other) to happen exactly in the order specified. This is often necessary when interacting with hardware, to prevent accesses that appear to do nothing, but actually affect the state of the hardware, from being optimised away. It gives no guarantees about the effect of unsynchronised accesses.

To avoid data races, you must use either atomic operations or explicit locks to synchronise access to shared objects. C++11 provides these in the standard library; if you're stuck in the past, then you'll have to rely on whatever libraries (such as pthreads) or language extensions (such as atomic intrinsics) are available on your platform.

C++ - What does volatile represent when applied to a method?

It is a volatile member which, just like a const member can only be called on const objects, can only be called on volatile objects.

What's the use? Well, globally volatile is of little use (it is often misunderstood to be applicable for multi-threaded -- MT -- programming, it isn't the case in C++, see for instance http://www.drdobbs.com/high-performance-computing/212701484), and volatile class objects are even less useful.

IIRC A. Alexandrescu has proposed to use the type checking done on volatile objects to statically ensure some properties usefull for MT programming (say that a lock has been taken before calling a member function). Sadly, I don't find the article back. (Here it is: http://www.drdobbs.com/184403766)

Edit: added links from the comments (they where added also in the question).



Related Topics



Leave a reply



Submit