Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the use of volatile keyword?

Tags:

c++

c

What is the use of volatile keyword in C/C++? What is the difference between declaring a variable volatile and not declaring it as volatile?

like image 259
kar Avatar asked Mar 04 '11 05:03

kar


People also ask

What is the use of volatile keyword in C?

The volatile keyword is intended to prevent the compiler from applying any optimizations on objects that can change in ways that cannot be determined by the compiler. Objects declared as volatile are omitted from optimization because their values can be changed by code outside the scope of current code at any time.

What is the use of volatile keyword in Java?

The volatile modifier is used to let the JVM know that a thread accessing the variable must always merge its own private copy of the variable with the master copy in the memory. Accessing a volatile variable synchronizes all the cached copied of the variables in the main memory.

Is volatile is a keyword?

Using volatile is yet another way (like synchronized, atomic wrapper) of making class thread-safe. Thread-safe means that a method or class instance can be used by multiple threads at the same time without any problem.

What is the volatile keyword and how it is used?

Volatile keyword is used to modify the value of a variable by different threads. It is also used to make classes thread safe. It means that multiple threads can use a method and instance of the classes at the same time without any problem. The volatile keyword can be used either with primitive type or objects.


4 Answers

The volatile qualifier on a variable tells the compiler that whenever you access this variable, its value has to be loaded from memory, and that the compiler may assume nothing about this value from previous stores it has effected.

So it is appropriate whenever you have situations where a variable may have a value that can not be foreseen in the current "thread of execution" (in a broad sense). This includes:

  • hardware registers
  • status variables in signal handlers
  • live variables that are used after unexpected jumps such as goto, switch/case, or, more important, setjmp/longjmp.

volatile is also necessary (but not sufficient!) for atomic access to thread shared variables to which the access is not mutexed. For that purpose volatile is by no means sufficient to guarantee the atomic access, even if it is just for reading. For that, you'd have to use special instructions of the CPU that are not modeled (or interfaced) by the abstract machine of the current C standard, C99. The next standard, C1X, is supposed to have such primitives.

like image 189
Jens Gustedt Avatar answered Sep 28 '22 12:09

Jens Gustedt


Volatile tells the compiler that the variable might change without it knowing - so it shouldn't optimise it away.

The only time I have ever needed it was in the days of ISA cards when you read a memory address to get the data from the bus. There was also a bug in the compiler which meant volatile didnt work!

It can also be useful in some parallel / mutli-threaded code

like image 35
Martin Beckett Avatar answered Sep 28 '22 12:09

Martin Beckett


Volatile tells to compiler that this value might change and the compiler should not do any optimization on it. An example of it.

/** port to read temperature **/
#define PORTBASE 0x40000000

unsigned int volatile * const port = (unsigned int *) PORTBASE; 

for(;;)
{
  if(*port == 300)
  {
     /** shutdown the system **/
  }

}

If port is not volatile, then the compiler will assume that the value cannot be changed. It will never do the checking if *port == 300. However, the value can be changed based on the sensor. We put volatile to tell compiler that don't do any optimization on it. Thumb rule is when using the memory mapped registers, whose value can change based on the circumstance, then use volatile keyword.

like image 23
dexterous Avatar answered Sep 28 '22 12:09

dexterous


For most C programs, the purpose of an object is to hold the last thing that was written by code in the current execution context ("thread", CPU core, etc.). The easiest way for a compiler to keep track of an object's contents is to allocate space in storage, and treat reads and writes of that variable as reads and writes of that storage, but the storage itself does not represent the purpose of the code--it merely represents a means to an end. Given unsigned x;, if a compiler sees x+=3; x+6;, the easiest way to generate code would be to fetch x, add 3, store the result to x, then fetch x, add 6, and store that result. The intermediate load and store, however, are only needed when the compiler doesn't know how to achieve the same effect some other way. A better compiler given such code would often be able to simplify it to simply add 9.

Especially in embedded or systems code, however, the purpose of a program may include loading and storing certain values from certain storage locations in a certain sequence. Many real-world machines perform I/O by having hardware which is triggered by loads and stores of certain objects, and performs various actions in response. For example, it would not be uncommon to have an object which would under the right conditions cause any character sent to it to be passed along to a terminal. Storing 'H' and then 'i' to SERTX, for example, might send Hi. Having a compiler try to simplify or consolidate such sequences (e.g. deciding to omit the store of 'H') would render the programs useless. A volatile qualifier indicates to the compiler that while it would be free to consolidate most accesses to most objects, there are a few for which such accesses need to be performed precisely as written. Effectively, one could imagine that for each scalar type (e.g. "unsigned") there are functions

int volatile_load_unsigned(unsigned volatile *p);
void volatile_store_unsigned(unsigned volatile *p, usigned value);

whose behavior the compiler knows nothing about, and thus code like:

extern volatile unsigned x;
x+=3;
x+=6;

would be interpreted by the compiler as equivalent to:

extern volatile int x;
volatile_store_unsigned(&x, volatile_load_unsigned(&x)+3);
volatile_store_unsigned(&x, volatile_load_unsigned(&x)+6);

In fact, the machine code to perform a volatile store is on most systems the same as the code for an ordinary store (and does not generate any kind of function call) but only the part of the compiler that generates the final machine code would "know" that--everything else should treat the code as though it was a function whose effects the compiler knew nothing about.

Unfortunately, in the name of "optimization", some compilers have ceased treating volatile accesses as calls to opaque functions. If code calls a function whose inner workings the compiler knows nothing about, it must assume that function may access any and all objects whose address has ever been exposed to the outside world. Applying such treatment to volatile-qualified variables will allow code to construct an object in ordinary storage, taking advantage of the ability to consolidate loads and stores, store the address of that object to a volatile-qualified pointer, triggering some other process which outputs the buffer. Code would need to test volatile-qualified object to ensure that the contents of the buffer had been output completely before doing anything else with that storage, but on implementations that follow the "opaque function" model the compiler would ensure that all writes to the storage which occurred in code before the volatile store that triggers the output operation would in fact generate store instructions which precede the instruction for the volatile store.

Some compiler writers think that it is more useful to have compilers assume they don't need to generate stores to non-qualified variables before performing accesses to volatile-qualified ones. Certainly the Standard does not require that implementations acknowledge the possibility that writing to a volatile variable might trigger actions that could affect other things, but that doesn't mean that a quality compiler for systems where such constructs can be useful shouldn't support them. Unfortunately, the fact that the authors of the Standard didn't want to mandate behaviors which would be useful on some systems but not others, has been interpreted as suggesting that compiler writers shouldn't support such behaviors even on systems where they are useful.

Note that on some processors, ensuring that one CPU executes instructions in a certain sequence may not be sufficient to ensure that the effects of that instruction occur in sequence. Some processors include configuration options so that operations on some parts of memory will be guaranteed to occur in order even when that would reduce execution speed, and some processors include other means of controlling execution order, but such issues are separate from volatile. On a quality implementation, volatile will ensure that the processor is at least made aware of all reads and writes that need to occur; a programmer may need to perform additional steps to ensure that the processor actually perform them as indicated, but telling the processor to complete all pending operations before it does anything else won't do any good if the compiler hasn't told the processor that something needs to get written.

like image 39
supercat Avatar answered Sep 28 '22 13:09

supercat