I have a piece of code that records the current time (DateTime.UtcNow
) as a "deadline", sets up an System.Threading.Timer
, and when the timer elapses checks if the deadline has been reached. It does this check by comparing the current time (DateTime.UtcNow
) to the recorded deadline.
Here is a simplified code example that illustrates the principle:
class DeadlineChecker
{
private DateTime deadline;
public DeadlineChecker()
{
int waitingTimeInMilliseconds = 1200;
TimeSpan waitingTime = TimeSpan.FromMilliseconds(waitingTimeInMilliseconds);
this.deadline = DateTime.UtcNow + waitingTime;
System.Threading.Timer timer = new System.Threading.Timer(TimerElapsed);
timer.Change(waitingTimeInMilliseconds, Timeout.Infinite);
}
private void TimerElapsed(object state)
{
if (this.HasDeadlineBeenReached())
{
[...] // Do something
}
[...] // Cleanup (dispose timer etc.)
}
private bool HasDeadlineBeenReached
{
get
{
// This is only called from TimerElapsed(), so
// this should always return true, right?
return (this.deadline <= DateTime.UtcNow);
}
}
}
I have now had a case where HasDeadlineBeenReached
unexpectedly returns false. It appears that my assumption that HasDeadlineBeenReached
always returns true in the example code above is wrong.
Can someone explain why? Before I refactor I would like to understand the issue.
Even taking the documented fact into account that DateTime.UtcNow
has a 15ms resolution, I would not have expected that two snapshots of DateTime.UtcNow
taken at times X and Y would report a time span that is smaller than what has actually elapsed (Y - X). Even if both snapshots are 15ms off, the time span between them should still be equal to the time that has elapsed due to the timer?
EDIT: What the real code tries to do is to set up a deadline, check that deadline when certain events occur, and "do something" when the deadline has been reached. The "timer elapsed" event is merely one of the many events that trigger the deadline check and is there to guarantee that "do something" happens in the absence of other events. It doesn't matter whether "do something" happens on time or a few milliseconds or even a second later than the deadline - there just needs to be a guarantee that it happens.
EDIT 2: I made a few minor changes to the code example after accepting the answer - bad style, I know, but maybe this makes the question a bit more intelligible to future generations.