C#中WaitOne()的虚假唤醒

时间:2017-04-13 08:31:55

标签: c# multithreading waitone spurious-wakeup

我的程序中有两个CRITERIA决定一个线程是等待还是继续。

第一条标准: 更改XML文件。我有一个文件观察器,如果XML文件发生变化,则设置AutoResetEvent_waitTillXmlChanges.Set()),因此线程应该继续。

第二个标准: 到期日已到。如果今天是文件传输应该发生的日期,则第二个标准已经满足,因此线程应该继续。

我当前的代码:

var waitTillNextWakeUpDay = NextWakeUpDay - DateTime.Now;
//SPURIOS WAKE-UP calls happening here
_waitTillXmlChanges.WaitOne(waitTillNextWakeUpDay);

我理解为了避免虚假的唤醒调用,while-loop附近放置WaitOne(),以便线程在错误唤醒的情况下再次进入等待模式。

问题:我不明白我应该如何实现围绕WaitOne()的故障安全while循环(这取决于两个条件)。

重要提示:由于每当XML文件发生变化时我都会在日志文件上打印,我可以说伪造的唤醒呼叫不是因为FileWatcher。最有可能的是,问题出在_waitTillXmlChanges.WaitOne(waitTillNextWakeUpDay)行,它不能等待waitTillNextWakeUpDay的时间跨度(大约1天)并且每15-30分钟就会清醒一次。

上面的代码在我的电脑上正常工作,但虚假唤醒的问题正在另一台PC上出现。

1 个答案:

答案 0 :(得分:0)

WaitHandle.WaitOne(TimeSpan timeout)的官方文档有一个奇怪的界限:

  

超时的最大值为Int32.MaxValue(2147483647)。

不确定这究竟是什么意思,但是TimeSpan.FromTicks(int.MaxValue)等于大约3分半钟,所以可能,这个方法不是'打算用于如此长时间的跨度。

WaitOne方法会返回bool,您需要检查一下,因为它可以在返回之前获得信号,因此您可以在循环中使用它,使用SpinWait struct或直接Thread.Yield()方法:

var waitTillNextWakeUpDay = NextWakeUpDay - DateTime.Now;
var spin = new SpinWait();
while (!eventToWait.WaitOne(waitTillNextWakeUpDay))
{
    // will define, which method to call:
    // Thread.Sleep(0), Thread.Sleep(1), or Thread.Yield()
    // based on number of spins
    spin.SpinOnce();

    // simply yield execution to other thread
    // Thread.Yield();
}

在此循环之后,您可以检查旋转的Count属性,以便获得唤醒次数。

旁注:您是否尝试远程调试服务?如果它在15-30分钟内唤醒,您可以通过远程调试器连接到它,并在代码中插入breakpoint,这可以帮助您定义问题的原因:

using System.Diagnostics;

Debugger.Break();