Search code examples
c#multithreadingconcurrencyvolatile

Code example proven to fail w/o volatile


Below is a C# code example which is a verbatim translation of a broken Java code (which has proven to break (i. e. the 2nd thread may fail to observe the change of sharedValue value) at least on Mac OS X 10.9, Java 1.8 (64 bit), Arrandale (1 socket x 2 core x 2 HT = 4 HW threads)):

using System;
using System.Threading;

class ThreadTest {
    /* volatile */ private int sharedValue;

    private void RunAsync() {
        while (this.sharedValue == 0);
    }

    private bool Test() {
        Thread t = new Thread(this.RunAsync);
        t.IsBackground = true;
        t.Start();

        Thread.Sleep(10);

        // Yes I'm aware the operation is not atomic
        this.sharedValue++;

        t.Join(10);
        bool success = !t.IsAlive;
        if (!success) {
            Console.Write('.');
        }
        return success;
    }

    static void Main() {
        long failureCount = 0L;
        const long testCount = 10000L;
        for (long i = 0; i < testCount; i++) {
            if (!new ThreadTest().Test()) {
                failureCount++;
            }
        }
        Console.WriteLine();
        Console.WriteLine("Failure rate: " + 100.0 * failureCount / testCount + "%");
    }
}

Amazingly, no matter many times I run the above C# code on .NET 4.0/Windows XP (32 bit), I haven't observed a single failure. Nor is there any failure when running on Mono (64 bit), Mac OS X. In both cases, I only see a single CPU core busy.

Can you suggest a C# code example which makes an incorrect use of a shared variable and fails unless the variable is marked volatile?


Solution

  • Try running the RELEASE build of the following program (do NOT run it from the debugger otherwise the demonstration won't work - so run the release build via "Debug | Start without debugging"):

    using System;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Demo
    {
        internal class Program
        {
            private void run()
            {
                Task.Factory.StartNew(resetFlagAfter1s);
                int x = 0;
    
                while (flag)
                    ++x;
    
                Console.WriteLine("Done");
            }
    
            private void resetFlagAfter1s()
            {
                Thread.Sleep(1000);
                flag = false;
            }
    
            private volatile bool flag = true;
    
            private static void Main()
            {
                new Program().run();
            }
        }
    }
    

    The program will terminate after a second.

    Now remove the volatile from the line

    private volatile bool flag = true; // <--- Remove volatile from this
    

    After doing so, the program will now never terminate. (Tested on Windows 8 x64, .Net 4.5)

    Please note, however, that in some cases it is more appropriate to use Thread.MemoryBarrier() rather than declaring the variable volatile, i.e.:

    while (flag)
    {
        Thread.MemoryBarrier();
        ++x;
    }
    

    For more information, see http://blogs.msdn.com/b/brada/archive/2004/05/12/130935.aspx