سؤال

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();
}
هل كانت مفيدة؟

المحلول

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.

نصائح أخرى

You can't do a controlled / blocking "wait" on a bool (although you probably don't need to, and Monitor might be more light-weight anyway).

As a cancel flag bool is fine, but you might want to make the bool volatile to prevent register cache being an issue.

Just using a bool won't work, you have to declare it volatile to tell the code generator that it should not store the value in a CPU register. The exact time that the thread will see the value set to true is unpredictable, it heavily depends on the kind of CPU your code runs on.

Ugly details, ones you can ignore when you use a WaitHandle.

The last argument should be False btw.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top