Volatile keyword in C# Threading


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

Volatile.jpg

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

Volatile1.jpg


Similar Articles