CLR Fun Stuff: How is my C# code converted into machine instructions?
Back in Dhaka, New Job

Multi-core CPU Caching: What is volatile?

I must give thanks to Jeffrey Richter for writing his wonderful book called CLR via C# as it cleared up the confusion about volatile keyword that I had.

How does CPU access variables in memory

We all have heard that CPUs have cache memory and having more cache memory at the CPU (L1,L2,L3) makes processing faster so when we buy a computer we try to buy it with a CPU with large cache memory. Why? The reason behind this is that in terms of CPU speed the RAM on motherboard is very slow. The memory that CPU has called cache memory is extremely faster than the normal memory.

So on the first run the CPU accesses the memory address and stores it in the cache. When the variable is accessed for the second time, it is returned from the cache. So all subsequent reads are done from the cache. The same thing happens for write operations as well. When the variable is changed, it is changed into the cache, also subsequent read/writes are done from cache. However the writes are eventually flushed into memory when cache is cleared or filled with other data. One of the intelligent things that the CPU does is when fetching the value of the variable (a few bytes) into the cache, it also fetches the values around it since the next variables to be used should be close by it.

Volatile1_2

This is fairly fine when you have only one CPU, but most of the PC and Laptops have multiple CPU. Now with the multiple processors this cache access can become problematic. With multi-core CPUs, true threading happens, two machine instructions get executed physically at the same time. Since two processors can have different caches, which are copies of the ram, they can have different values

In x86 and x64 processors (according to Jeffrey’s book) are designed to sync the caches of different processors so we may not see the problem. But the IA64 processor takes the advantage of the fact that each processor has its own cache and does not synchronize rigorously. So different threads executing may have put in different values in the cache.

Please note that one CPU may write to the its own cache, which will eventually be transferred to RAM, the other CPU may have read from the RAM which contained old value since the first CPU has not updated the value yet. See below (click on image for larger view)

Volatile2

So this creates an obvious concurrency problem. That is where the volatile keyword comes in. If you declare a field volatile it is always read from memory and written into memory immediately. However it must be noted that all interlocked operation (again thank to Jeffrey) like lock, Monitor, Mutex, Semaphore etc synchronizes the caches. So this volatile keyword is not needed for those.

But volatile variables are slower. It would have been great if there was a write volatile only variable.

kick it on DotNetKicks.com

Comments

Moim Hossain

Again a good post.
I would like to add a bit more though. volatile variables are pretty useful while doing multi threading work, disregarding the number of CPU. While I used to write code in good-old C/C++ I came to know that, if there is a code snippet like..

int i = 0; // declare some where globally

//...then in some method

for( i = 0; i < 1024; ++ i)
{
// do something useful
}

Now assume some other method running concurrently that evaluates the value of i.

In this case, the compiler will optimize the variable i before starting the loop. it will initialize i with 0 before starting the loop and then load the value into the CPU register and will increment it directly into the register.
so the actual i in memory will hold zero for all the time the loop continues. Eventually when the loop terminates, the memory variable will be updated with the value 1024.
Therefore, if any other thread try to read the value of i during the looping, it will always find a zero and all of a sudden it will find a value 1024.
So if we need to get each iteration value for i in memory -from all thread, we need to declare the i as volatile.
if it is declared as volatile compiler will not optimize it during the loop incrementation.

I guess this was the primary theory inventing the key word volatile...(I am talking about the context of Turbo C, C++ while ppl were using 8086, and there was not even dreams of multiple CPU. )

Thanks shiplu bhai again for an informative post.

Moim Hossain

A quick experiment can be shown here..

public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private int i = 0;

private void button1_Click(object sender, EventArgs e)
{
for (i = 0; i 0)
{
found = "YEAP";
}
}

private void button2_Click(object sender, EventArgs e)
{
this.Text = found;
}
}

In to the above code, if the i can be read something other than zero then the string found will hold a value YEAP. But it never happens. So alike C, C++ , C# is also not an exception.

Moim Hossain

:( some how the code snippet is getting screwed.

private int i = 0;

private void button1_Click(object sender, EventArgs e)
{
for (i = 0; i 0)
{
found = "YEAP";
}
}

private void button2_Click(object sender, EventArgs e)
{
this.Text = found;
}

Peter

But volatile variables are slower. It would have been great if there was a write volatile only variable.

look at ->

Thread.VolatileWrite

Verify your Comment

Previewing your Comment

This is only a preview. Your comment has not yet been posted.

Working...
Your comment could not be posted. Error type:
Your comment has been saved. Comments are moderated and will not appear until approved by the author. Post another comment

The letters and numbers you entered did not match the image. Please try again.

As a final step before posting your comment, enter the letters and numbers you see in the image below. This prevents automated programs from posting comments.

Having trouble reading this image? View an alternate.

Working...

Post a comment

Comments are moderated, and will not appear until the author has approved them.

Your Information

(Name and email address are required. Email address will not be displayed with the comment.)