Introduction
The volatile keyword is a convenience keyword
for those who need to access member variables of a class or structure in
multi-threaded conditions.
The purpose of the volatile keyword is to tell
the compiler that the variable you are marking as volatile may be accessed by
multiple threads. There are certain optimizations that the csharp compiler makes
when it compiles our code and unless the variable is marked as volatile, the
compiler will make optimizations assuming that the variable will only be
accessed by one thread at a time.
Note that the volatile keyword can only be used
against the following types of data:
-
Reference types
-
Pointer types (in an unsafe context). Note that although the pointer itself
can be volatile, the object that it points to cannot. In other words, you
cannot declare a "pointer to volatile."
-
Types such as sbyte, byte, short, ushort, int, uint, char, float, and bool
-
An enum type with one of the following base types: byte, sbyte, short,
ushort, int, or uint
-
Generic type parameters known to be reference types
-
IntPtr and UIntPtr
Variables that are objects or
structures will need to use other locking mechanisms. Only variables that are
members of classes or structures can be declared as volatile.
To declare a variable volatile, just add
volatile as one of the variable modifiers.
class
Akshay
{
private
volatile int m_multiThreadVar;
}
In the following example,
there are two static fields one field is a object reference of string type, and
the other is a volatile bool value type. In the Main method, a new thread is
created, and the SetVolatile method is invoked. In SetVolatile, both the fields
are set.
using
System;
using
System.Threading;
namespace
VolatileInThreading
{
class Akshay
{
static string
result;
static volatile
bool done;
static void
SetVolatile()
{
result = "Csharpcorner.com";
done = true;
}
static void
Main(string[] args)
{
new
Thread(new
ThreadStart(SetVolatile)).Start();
Thread.Sleep(200);
if (done)
{
Console.WriteLine(result);
}
Console.Read();
}
}
}
Output
When multiple threads execute at once, this can
cause serious problems. Please keep in mind that the volatile modifier does not
force synchronization of loads and stores; instead it simply tells the compiler
not to change the order of accesses to the field. By eliminating reordering
optimizations, the code becomes more predictable from a programmer's
perspective.
Again, since this is an advanced csharp concept
this is probably something that most of you will not need to worry about using,
especially in ASP.NET. However, there have been times when I've used
multithreading in an ASP.NET application (for screen scraping performance) so it
is not completely out of the realm of possibility for you to need to know
something about how to do multi-threaded programming. If you do, you'll be glad
you learned about the volatile keyword.
After studying more about volatile I found three
portable uses for volatile. I'll summarize them here.
-
Marking a local variable in the scope of a
setjmp so that the variable does not rollback after a longjmp
-
Memory that is modified by an external agent
or appears to be because of a screwy memory mapping
-
Signal handler mischief.
We have another example in which a
worker thread can be created and used to perform processing in parallel with
that of the primary thread.
using
System;
using
System.Threading;
namespace
VolatileInThreading
{
public class
Worker
{
private
volatile bool shouldStop;
public void
DoWork()
{
while (shouldStop)
{
Console.WriteLine("Worker
thread: working...");
}
Console.WriteLine("Worker
thread: terminating gracefully.");
}
public void
RequestStop()
{
shouldStop = true;
}
}
public class
WorkerThreadExample
{
static void
Main()
{
Worker workerObject =
new Worker();
Thread workerThread =
new Thread(workerObject.DoWork);
workerThread.Start();
Console.WriteLine("Main
thread: starting worker thread...");
while (!workerThread.IsAlive) ;
Thread.Sleep(1);
workerObject.RequestStop();
workerThread.Join();
Console.WriteLine("Main
thread: worker thread has terminated.");
Console.Read();
}
}
}
Output