.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++;
}
}
}