1

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.

VMAtm
  • 27,943
  • 17
  • 79
  • 125
skm
  • 5,015
  • 8
  • 43
  • 104
  • What class is `_waitTillXmlChanges`? – David Schwartz Apr 13 '17 at 08:37
  • @DavidSchwartz: `_waitTillXmlChanges` is of `AutoResetEvent` type. – skm Apr 13 '17 at 08:38
  • You could change the type. But if you really want to use an `AutoResetEvent`, you should have a counter that is incremented before the event is signaled. Before calling `WaitOne`, note the value of that counter. The `while` loop should continue if the counter has not been incremented. (An AutoResetEvent doesn't keep the right state for your application, so you'll have to keep the state yourself.) – David Schwartz Apr 13 '17 at 08:41
  • So you mean you only signal the event in one place (when xml changes) but your `WaitOne` returns when that did not happen AND you are completely sure `waitTillNextWakeUpDay` timeout is not yet passed? – Evk Apr 13 '17 at 08:43
  • @Evk: I am completely sure that the XML is not changed since I write it to a log file when it changes. I am also writing all the dates in a log file. I am absolutely sure that the `WaitOne()` is not waiting till the `waitTillNextWakeUpDay` timeout is passed out. I have been monitoring the application since yesterday. Last night, it did wait for 17 hours but since morning it getting awake random timespans (2 minutes, 15 minutes, 17 minutes, 27 minutes etc.) – skm Apr 13 '17 at 08:48
  • And your calculation of `NextWakeUpDay - DateTime.Now` cannot be wrong somehow? – Evk Apr 13 '17 at 08:50
  • @Evk: No, that's also not possible. The log file says `NextWakeUpDay: Day: 14 Month: 4 Year: 2017 AT: 08:10:00` and `DateTime.Now: Day: 13 Month: 4 Year: 2017 AT: 09:29:28.4560140`. So, baiscally it should sleep till tomorrow but it got wake-up after 12 minutes. – skm Apr 13 '17 at 08:52
  • What is return value of `WaitOne`? – Valery Petrov Apr 13 '17 at 09:10
  • He doesn't know. And that's the bug, FSW generates events even if the file did not change. Like an update to the directory entry's LastAccessTime. – Hans Passant Apr 13 '17 at 09:18
  • @HansPassant: If the FSW records a file changed event then, I am noting down that event in the log file that XML has been changed and then execute the `_waitTillXmlChanges.Set();` . If the problem is because of FSW's bug then, still I would get the "file changed" entry in the log file. Since, I have not received any such entry, it means that `WaitOne()` got awake without executing the `waitTillNextWakeUpDay` TimeSpan. – skm Apr 13 '17 at 09:26

1 Answers1

0

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();
VMAtm
  • 27,943
  • 17
  • 79
  • 125
  • I already read it before that the maximum timeout is `Int32.MaxValue (2147483647)`. The value `2147483647` is in milliSeconds which is equal to nearly `24 days`. But in my case, the thread was supposed to wait for one day only, which it couldn't (but sometimes it does). – skm Apr 13 '17 at 14:50
  • Yeah, so did you try to examine the `return` value of it, as I suggested in second part of my answer? – VMAtm Apr 13 '17 at 14:54
  • I tried to do the Remote debugging for something else but I couldn't even manage to do it. My code is Managed code for which I need to run the Remote Debugging tool on target machine in `Windows Authentication Mode` and when I do so, I am not able to login with my PC. – skm Apr 13 '17 at 14:54
  • no, I did not examine the `return` value. All I have is a log file as mentioned in my question. – skm Apr 13 '17 at 14:57
  • Ok, so what about the `return` value of the `eventToWait.WaitOne`? Did you log it? – VMAtm Apr 13 '17 at 14:57
  • @skm So you now have the `while` loop, as you wanted :) Give it a try – VMAtm Apr 13 '17 at 14:58
  • 1
    yes, I have already implemented an another logic with a failsafe `while-loop` and it is working fine so far (I am examining it). I will use your method if my thread again gets spurious wake-up calls. – skm Apr 13 '17 at 15:00