.net 是否有任何理由在bool上使用WaitHandle来标记取消?

.net 是否有任何理由在bool上使用WaitHandle来标记取消?,.net,multithreading,synchronization,waithandle,.net,Multithreading,Synchronization,Waithandle,我继承了一些线程化的代码,在回顾它之后,我发现类似这样的结构(在后台线程方法中): 通常有一个公共或私有的Stop()方法,如下所示: public void Stop() { stopEvent.Set(); bgThread.Join(); } 我的问题是:在这里使用等待句柄有什么用?似乎这样做是为了确保停止信号是一个原子操作,但我认为写入布尔值无论如何都是原子操作。如果是这种情况,是否有任何理由不使用以下内容: private void Run_Thread() {

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

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

public void Stop() {
    stopEvent.Set();
    bgThread.Join();
}
我的问题是:在这里使用等待句柄有什么用?似乎这样做是为了确保停止信号是一个原子操作,但我认为写入布尔值无论如何都是原子操作。如果是这种情况,是否有任何理由不使用以下内容:

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

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

写入
bool
变量确实是原子性的,但除非该变量也是可变的(或引入其他同步),否则它可能无法从其他线程中看到。这些问题可能很难追踪和重现

例如,在我的x64笔记本电脑上,以下程序会正确停止。在我的x86上网本上,它永远挂起。(都是用csc/o+Test.cs编译的)

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


当然,通常使用标志以外的东西的更好的理由是,如果你想等待某个条件,不管是“有新项目”还是“我被取消了”(或两者都有),而不需要紧循环。

你不能在bool上执行受控/阻塞“等待”(尽管您可能不需要这样做,而且显示器可能更轻)


由于取消标志bool可以,但您可能希望使bool易失性,以防止寄存器缓存成为问题。

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

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


最后一个参数应该是False,顺便说一句。

您的stop方法需要调用
bgThread.Join()
在我的代码库中是
true
——说实话,我不理解这个参数,所以我不想偏离代码中的内容。忽略它,WaitOne()会有一个重载这只需要超时。它被添加到.NET 2.0 service pack 1中,因为太多的程序员也不知道它的意思,并且弄错了。这就是问题所在-这段代码实际上并没有等待这个等待句柄,它只是将它用作一个标志。
volatile
提示+1。谢谢Jon-不幸的是,我仍然停留在.NET 3.5中;其他人还有一个问题——你提到过使用
volatile
——将变量标记为
volatile
,有什么坏处吗?你不能再通过“ref”来使用该变量,你会失去可能的CLR优化,但这就是“volatile”的含义:)@vtortola:您可以将变量用作
ref
参数,但是您会得到警告,并且波动性不会保留在调用的方法中。这就是我想说的意思,我没有很好地解释自己:P
private void Run_Thread() {
    while(!stop) {
        // code here
    }
}

public void Stop() { 
    stop = true;
    bgThread.Join();
}
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++;
        }
    }
}