Difference between the const and volatile qualifier in C

Const keyword in C programming language

Constants in C can be defined using “const” qualifier. What it means is that memory location whose value cannot be changed during its life time. Lets see an example

int main ()
{
const int x = 10;
printf (“X is %d\n”, x);
x = 5;
printf (“X is %d\n”, x);
return 0;
}

You can see that the above program cannot compile. Because you are assigning value to a const more than once. As I said, its value cannot be changed. You can read the value of a constant as many times as you want, but you can assign its value only once.

Volatile keyword in C programming language

Lets move to “volatile”. To understand the use of volatile qualifier you would have to know multi-threading and some knowledge of Computer Architecture.
Let us first see, how a compiler optimizes a variable. Let us take the help of code below:

int main ()
{
int x;
x = 10;
x++;
return 0;
}

We know that a variable represents a memory location. Hence, x would have some memory location, let it be 1000.

  • The control is first at the Line 1, when compiler will allocate some memory to x, starting at location 1000.
  • Then we get to Line 2. To assign, a value to x. CPU will copy “10” to the memory location to 1000.
  • Similarly, for Line 3, CPU will add 1 to that memory location.

All above operation includes CPU operating on the memory. The problem with this approach is, it is slow, as this would include a lot of Bus communication between CPU and Processor. So, what compiler do is it do some optimizations. These optimizations includes using Registers of a CPU, operating on them and then copying the value from Register to memory when required. Registers are actually the fastest way of communication with a CPU.
So, lets see how compiler will perform with above code using registers.

  • As usual, compiler will first allocate some memory to x, starting at location 1000.
  • When, it encounters Line 2. Compiler thinks that, why use the CPU-Memory communicaton? Why not use the fastest method using Registers? So, it will actually store value 10 into a Register, say A.
  • At Line 3, as value was stored in Register A not in the memory, then it will increment the value inside the Register not memory.
  • If it wants to it can copy the value of Register A back into the memory location of x.

Now lets enter into world of MultiCore CPUs and Multithreading. In a MultiCore CPU, there are more than one core. Let us assume there are 2 Cores. Each Core has its own set of Registers. A thread is an independent unit of execution inside a process. With multithreading you can perform more than one tasks simultaneously using more than one threads.
Let us have a program.

int x;
void thread_func ()
{
for (int i = 0; i < 1000; i++)
{
x += 2;
}
}

int main ()
{
pthread_t *th1, *th2;
x = 0;
th1 = pthread_create (thread_func);
th2 = pthread_create (thread_func);
}

Pthread is a POSIX Library to create a thread. Here two threads are created. Both of them runs the same function “thread_func”. In thread_func, x is accessed here x is now global variable. Let two threads are running on two different cores. Let us assume that compiler has done the same optimizations and will use the fast method of Registers.
For Thread 1, th1:

  • At Line 1, of thread_func value of x has been assigned. This value is stored in Register A of Core 1.
  • Then the loop runs and in each iteration of loop, 2 is added to Register A.
  • At the end, 2000 will be added to x through Thread 1.

Similarly for Thread 2, 2000 will be added.
So, at the end we should get the value 4000 (2000 + 2000) isn’t it?
But we will not.
The reason being, x is a global variable and its is accessed by two Threads on two different cores. Each Core will have its own copy of x in the Register. There is no way that Core 1 could know what is the value of x in the Register of Core 2 and vice-versa. To, solve this issue “volatile” qualifier is used.

If Compiler detects a volatile variable (variable declared with “volatile” qualifier), then it will not perform any kind of optimizations over it. Every time, a Core wants to operate on x then it will have to take the value from the memory, then operate on it and then store that value back into the memory. This is the work of “volatile” keyword to tell the compiler not to do optimizations over this variable.

PS:- To get the 4000 result, you would also have to use Thread Synchronization Techniques. Volatile is mostly used with Thread Synchronization.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s