C# Monitor.Wait() 是否存在虚假唤醒?

51

Java的 Object.wait() 警告存在“虚假唤醒”,但是C#的 Monitor.wait() 似乎根本没有提到它。

考虑到Mono是在Linux之上实现的,而Linux存在虚假唤醒,这不应该在某个地方进行记录吗?

1个回答

90

Joe Duffy的Windows并发编程提到了这一点(P311-312,P598)。这段话很有趣:

请注意,在上述所有示例中,线程必须对所谓的虚假唤醒具有弹性-使用条件变量的代码应在即使在被过早唤醒(即在寻找的条件已经建立之前)的情况下仍保持正确和活跃。这不是因为实现实际上会做这些事情(尽管其他平台(如Java和Pthreads)上的某些实现已知会这样做),也不是因为代码将在不必要时有意地唤醒线程,而是由于没有关于何时唤醒已被唤醒的线程将被调度的保证。条件变量不公平。可能-甚至很可能-另一个线程将获取相关锁并再次使条件为false,然后唤醒线程没有机会重新获取锁并返回临界区。

然后他给出了测试条件的while循环的正常模式。

我认为从这个可以合理地预期Monitor.Wait通常不会让您过早地醒来,并且如果您绝对知道没有其他东西可以更改条件,那么您可能可以不包括条件循环:但是为了安全起见,最好还是包括它,以防逻辑不准确。


2
我直接向乔核实,看看我的推断是否正确。 - Jon Skeet
乔有回复你关于那个问题吗?在同一本书的第207页,他指出CLR在任何阻塞时都使用一个公共(可警报)等待例程,包括对Monitor的阻塞调用。这是否意味着除了您提到的“表面上”虚假唤醒之外,您的Wait还可能受到异步过程调用引起的“真正”的虚假唤醒的影响? - Daniel Fortunov
3
除了在Windows 2000、XP和7上的Java之外,我已经完全证明虚假唤醒确实会发生,原因可能是硬件问题-尽管C#可能无法避免Java无法避免的情况,但这不太可能发生。 - Lawrence Dol
@SoftwareMonkey:好吧,我肯定会“做正确的事情”,并假设它可能发生-但我不认为我自己曾经见过它。稍微编辑一下。 - Jon Skeet
2
现在这很有趣,也很令人困惑。两个不同的概念似乎被归为同一个名称“虚假唤醒”。真正的虚假: “在建立条件之前就被唤醒[...]”。有点类似于过度睡眠:在条件再次被证明为假后预定。如果调度程序能够将“唤醒”等同于“预定”,那么第二个问题就会消失。 - YvesgereY
3
这篇由 Raymond Chen 撰写的简短文章表明,在 Win32 条件变量中存在虚假唤醒现象。根据他描述的原因,这意味着这些条件(被窃取的唤醒、过度唤醒)很可能是类似的 Win32 同步机制的一部分。 - Kent

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接