有没有理由在bool上使用WaitHandle来标记取消?

Eri*_*bes 3 .net multithreading synchronization waithandle

我继承了一些线程代码,在查看它之后,我发现了这样的结构(在后台线程方法中):

private ManualResetEvent stopEvent = new ManualResetEvent(false);

private void Run_Thread() {
    while (!stopEvent.WaitOne(0, true)) {
        // code here
    }
}
Run Code Online (Sandbox Code Playgroud)

通常有公共或私人Stop()方法,如下所示:

public void Stop() {
    stopEvent.Set();
    bgThread.Join();
}
Run Code Online (Sandbox Code Playgroud)

我的问题是:在这里使用等待句柄可以提供什么?似乎这样做是为了确保停止的信号是原子操作,但我认为写入布尔值无论如何都是原子的.如果是这种情况,是否有任何理由不使用以下内容:

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

public void Stop() { 
    stop = true;
    bgThread.Join();
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 7

写入bool变量确实是原子的,但除非变量也是易失性的(或者你引入了一些其他的同步),否则它可能从其他线程中看不到.这些问题很难追查和重现.

例如,在我的x64笔记本电脑上,以下程序正确停止.在我的x86上网本上,它永远挂起.(两者都编译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++;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在这种特殊情况下,使用volatile标志似乎是合理的 - 尽管如果你使用.NET 4,最好使用Task取消机制:)

当然,通常使用除标志之外的其他东西的更好的理由是,如果你想要等待一些条件 - 无论是"是否有新项目"或"我被取消"(或两者) - 没有紧密循环.