2015-05-13 144 views
3

注意:我受限于.NET 3.5,因此我无法使用ManualResetEventSlimEventWaitHandle是否必须处理虚假唤醒?

我必须做这样的事情的时候,处理Spurious wakeups

var waitHandle = new EventWaitHandle(); 
new Thread(() => 
{ 
    Thread.Sleep(TimeSpan.FromSeconds(5)); 
    waitHandler.Set(); 
}); 
waitHandle.WaitOne(); 

如果是这样,是正确的内存屏障设置呼叫Set和/或WaitOne当这样,这将是安全的:

var reallyDone = false; 
var waitHandle = new EventWaitHandle(); 
new Thread(() => 
{ 
    Thread.Sleep(TimeSpan.FromSeconds(5)); 
    reallyDone = true; 
    waitHandler.Set(); 
}); 
while (!reallyDone) 
    waitHandle.WaitOne(); 

特别是,这个例子中的主线程有可能因为指令重排序或缓存而看不到reallyDone设置为true?在这种情况下,reallyDone需要是易失性还是​​不必要?

+1

没有虚假唤醒。如果有这样的事情,几乎所有的Windows程序都会中断。你在与风车搏斗。但是,是的,同步功能执行完整的内存屏障(这是很好理解,但没有记录)。 – usr

+0

我不同意:https://msdn.microsoft.com/en-us/library/windows/desktop/ms682052%28v=vs.85%29.aspx“条件变量受到虚假唤醒的影响(那些不相关的并且唤醒被唤醒(另一个线程在唤醒线程之前运行)因此,在睡眠操作返回之后,您应该重新检查谓词(通常在while循环中)。“ 也在.NET 4.0+中有这样的代码:http://referencesource.microsoft.com/#mscorlib/system/threading/ManualResetEventSlim.cs,635“//应对来自其他正在取消等待的虚假唤醒的循环“ –

+1

事件不是一个条件变量。这不适用。源代码告诉你,框架为你处理这种情况。虚假唤醒不会暴露给用户代码。它们是您在那里挖掘的实现细节。 – usr

回答

2

事件(MRE,ARE和瘦身版本)没有虚假唤醒。如果这些对象存在这样的事情,几乎所有的Windows程序都会中断。你在与风车搏斗。但是,是的,包括等待和设置事件在内的许多同步功能都会执行完整的内存屏障(很好理解,但没有记录)。条件变量允许虚假唤醒(如文档状态)。他们与事件无关。

此外,为什么会有虚假唤醒?从API的角度来看没有意义。该事件可能只是在内部循环,并隐藏你的虚假唤醒(实际上,MRESlim是这样做的)。我只能重复一遍:几乎所有的程序都会中断。这不是现实。

The docs say:

阻塞当前线程,直到当前的WaitHandle接收信号。 此方法的调用方无限期地阻塞,直到当前实例接收到一个信号。

如果虚假唤醒存在于事件的上下文中,这些语句将是错误的。

你错误地解释了你所看到的。你有一个错误,但不是由事件引起的。 reallyDone技术不是必需的。

+0

挖掘参考资料来源,它确实显示'WaitHandle'没有像上面注释中提到的那样被条件变量支持。相反,它们是由事件对象支持的,正如你所提到的那样,它没有虚假的唤醒。有关事件对象的更多信息,请访问:https://msdn.microsoft.com/en-us/library/windows/desktop/ms686915(v=vs.85).aspx –

相关问题