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

时间:2011-03-22 19:15:04

标签: .net multithreading synchronization waithandle

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

private ManualResetEvent stopEvent = new ManualResetEvent(false);

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

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

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

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

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

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

3 个答案:

答案 0 :(得分:7)

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

例如,在我的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++;
        }
    }
}

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

当然,通常使用旗帜以外的其他东西的更好理由是,如果你想等待一些条件 - 无论是“有新物品”还是“我被取消”(或两者都有) - 没有紧张 - 循环。

答案 1 :(得分:1)

你不能对bool进行控制/阻止“等待”(尽管你可能不需要,而且监视器可能更轻量级)。

作为取消标志 bool很好,但你可能想让bool变得易失,以防止寄存器缓存成为问题。

答案 2 :(得分:1)

只是使用bool不起作用,你必须声明它 volatile 告诉代码生成器它不应该将值存储在CPU寄存器中。线程将值设置为true的确切时间是不可预测的,这在很大程度上取决于代码运行的CPU类型。

丑陋的细节,当您使用WaitHandle时可以忽略的细节。

最后一个参数应为False btw。