Search code examples
.netmultithreadingsynchronizationwaithandle

Is there any reason to use a WaitHandle over a bool to flag for cancellation?


I've inherited a bit of threaded code, and upon reviewing it, I'm finding structures like this (within a background thread method):

private ManualResetEvent stopEvent = new ManualResetEvent(false);

private void Run_Thread() {
    while (!stopEvent.WaitOne(0, true)) {
        // code here
    }
}

Usually there's a public or private Stop() method, like so:

public void Stop() {
    stopEvent.Set();
    bgThread.Join();
}

My question is this: What is served by using a wait handle here? It seems as though this is done to ensure that signalling for a stop is an atomic operation, but I thought writing to a boolean was atomic anyway. If that's the case, is there any reason not to just use the following:

private void Run_Thread() {
    while(!stop) {
        // code here
    }
}

public void Stop() { 
    stop = true;
    bgThread.Join();
}

Solution

  • Writing to a bool variable is indeed atomic, but unless the variable is also volatile (or you introduce some other synchronization) then it might not be visible from other threads. Such problems can be hard to track down and reproduce.

    For example, on my x64 laptop, the following program stops correctly. On my x86 netbook, it hangs forever. (Both compiled with csc /o+ Test.cs).

    using System;
    using System.Threading;
    
    class Test
    {
        static bool stop = false;
    
        static void Main(string[] args)
        {
            new Thread(CountLots).Start();
            Thread.Sleep(100);
            stop = true;
            Console.WriteLine("Finished...");
        }    
    
        static void CountLots()
        {
            long total = 0;
            while (!stop)
            {
                total++;
            }
        }
    }
    

    In this particular case it seems reasonable to use a volatile flag - although if you're using .NET 4 it would be better to use the Task cancellation mechanisms :)

    Of course normally a better reason for using something other than a flag is if you want to wait for some condition - whether that's "is there a new item" or "have I been cancelled" (or both) - without tight-looping.