#606 – Use volatile Keyword to Fix Problems With Reading/Writing Shared Data

When you read data from one thread but write the data from a different thread, you can run into a problem where the thread reading the data will read stale/incorrect data.

You can prevent this behavior by marking the data field in question with the volatile keyword.  This indicates to the compiler that no optimizations should be done with respect to the storage location of this field and will prevent the problem of reading stale data.

Below is the earlier example, updated to include the volatile keyword.

        public static volatile bool runFlag = true;

        private static void RunUntilYouStopMe()
        {
            int i = 0;

            while (runFlag)
            {
                i++;
            }

            Console.WriteLine("I'm stopping");
        }

        static void Main()
        {
            Thread runThread = new Thread(new ThreadStart(RunUntilYouStopMe));
            runThread.Start();

            Thread.Sleep(1000);

            runFlag = false;
            Console.WriteLine("Main() has set runFlag to false");

            while (true)
            {
                Console.ReadLine();
                Console.WriteLine(".. runThread.IsAlive={0}", runThread.IsAlive);
            }
        }

Before the fix:

After the fix:

#605 – The Causes of Problems With Reading/Writing Shared Data from Multiple Threads

When you read data from one thread but write the data from a different thread, you can run into a problem where the thread reading the data will read stale/incorrect data.

The problem happens when the compiler, the runtime environment (e.g. JIT compiler) or the hardware optimizes the code in such a way that a thread ends up reading stale data and doesn’t have access to newer data written by a different thread.  As part of standard optimization techniques, a compiler may change the order of instructions being executed or it may choose to store a data value in a local register for efficiency.  When the latter occurs, one thread effectively ends up working with a different copy of the data.

To avoid these problems, you can do one of two things:

  • Protect access to the shared data using sychronization techniques
  • Use the volatile keyword for shared data fields