Spurious wake-up of WaitOne() in C#

578 views Asked by At

There are two CRITERIA in my program which decides whether a thread should wait or continue.

First Criterion: Change in an XML file. I have a file watcher which sets an AutoResetEvent (_waitTillXmlChanges.Set()) if the XML file changes and hence the thread should proceed.

Second Criterion: Due Date has come. If today is the date when the file transfer should take place then, the second criterion has met and hence the thread should proceed.

My Current Code:

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

I understand that to avoid the spurious wake-up calls, a while-loop is put around the WaitOne() so that the thread goes into waiting mode again if it woke-up by mistake.

PROBLEM: I don't understand how should I implement the failsafe while loop around the WaitOne() (which depends on two conditions).

Important Clue: Since I am printing on a log file whenever the XML file changes so, I can say that the fake wake-up calls are not because of the FileWatcher. Most probably, the problem is in the line _waitTillXmlChanges.WaitOne(waitTillNextWakeUpDay), which is not able to wait for a timespan of waitTillNextWakeUpDay (which is around 1 day) and gets awake in every 15-30 minutes.

The above code is working as desired on my PC but the problem of spurious wake-up is coming on an another PC.

1

There are 1 answers

7
VMAtm On

Official docs for WaitHandle.WaitOne(TimeSpan timeout) has a strange line:

The maximum value for timeout is Int32.MaxValue (2147483647).

Not sure what exactly this means, but the TimeSpan.FromTicks(int.MaxValue) is equal to about 3 and half minutes, so, maybe, this method isn't intended for usage for such long time spans.

WaitOne method returns a bool, and you need to check that, as it can return before it got the signal, so you can use it in a loop, using with either SpinWait struct or with direct Thread.Yield() method:

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();
}

After this loop you may examine the Count property for your spin, so you'll got the number of wake ups.

Side note: did you try to remote debugging your service? If it wake up in 15-30 minutes, you can connect to it via remote debugger, and hit a breakpoint by inserting this in your code, this can help you to define the reason of your problem:

using System.Diagnostics;

Debugger.Break();