0

There are many questions about C# System.Threading.Timer on SO, but I cannot find this exact question.

In our code, we need to ensure that a timer fires after, and I mean after, a given amount of time. If the timer fires .00001 seconds early, then that's bad. On the other hand, if the timer fires even a few seconds late, that's OK.

I made this dotnetfiddle to show that the timer sometimes fires early. Run it a few times and you'll see it (or increase numSamples in the code). On my local PC, I've checked other time spans and they behave similarly, but dotnetfiddle doesn't allow your code to execute too long so TimeSpan.FromSeconds(1) is what's in that demo.

One hack-ish way I've thought is to just sleep for a tenth of a second and that seems to catch the fuzzy-ness around Timer's inaccuracy. Is there a canonical way to make sure that a time actually fires after a given time? I know there are more accurate timers in C#, but since our requirements allow for some wiggle room after the due time I figured there might be something cheaper that I've overlooked.

Thanks to @PaulF and @AlexeiLevenkov for your comments. I think I fell victim to the XY problem. My main concern was that the underlying "ground truth" for the time in the code I'm working in is DateTime's time. Trying to have an accurate timer with respect to an inaccurate "ground truth" is flawed. I gave the answer I came up with below, and will accept it in the future.

Frank Bryce
  • 8,076
  • 4
  • 38
  • 56
  • 3
    You should not be relying on DateTime for that degree of accuracy. Note that you are printing time values with a far greater precision than the accuracy of DateTime & despite apparently firing too early they may be firing at the correct time. See this article : https://blogs.msdn.microsoft.com/ericlippert/2010/04/08/precision-and-accuracy-of-datetime/ – PaulF Jul 28 '16 at 16:10
  • 1
    If you know when next event should happen why not to compute interval every time? Notes - timers already fire after specified amount of time... As PaulF noted using 2 different sources/precision of time is likely another source of problems discussed in http://stackoverflow.com/questions/2432160/c-sharp-timer-getting-fired-before-their-interval-time?rq=1. – Alexei Levenkov Jul 28 '16 at 16:24

3 Answers3

0

in your timer ElaptseHandler use thread.Sleep(100) or any amount you think fit to delay the actuall excution of your code

Timer timer = new Timer(1000);
          timer.Elapsed += async ( sender, e ) => await HandleTimer();
          timer.Start();

 private static Task HandleTimer()
   {
     Thread.Sleep(100);
      //YOUR CODE HERE
   }
suulisin
  • 1,414
  • 1
  • 10
  • 17
  • Note: Thread.Sleep should only be used if you are actually in a worker thread; using it on the main thread will freeze the program for the duration of the sleep, which is probably not what OP wants! – ekolis Jul 28 '16 at 17:00
0

Why don't use quarzt.net here I have used and it's very easy to implement with nugget.

 // construct a scheduler factory
ISchedulerFactory schedFact = new StdSchedulerFactory();

// get a scheduler
IScheduler sched = schedFact.GetScheduler();
sched.Start();

// define the job and tie it to our HelloJob class
IJobDetail job = JobBuilder.Create<HelloJob>()
    .WithIdentity("myJob", "group1")
    .Build();

// Trigger the job to run now, and then every 40 seconds
ITrigger trigger = TriggerBuilder.Create()
  .WithIdentity("myTrigger", "group1")
  .StartNow()
  .WithSimpleSchedule(x => x
      .WithIntervalInSeconds(40)
      .RepeatForever())
  .Build();

sched.ScheduleJob(job, trigger);

taken from website http://www.quartz-scheduler.net/documentation/quartz-2.x/tutorial/using-quartz.html

0

Inside of the Timer handler, I put a piece of code in there like below. This is not what I wanted to do, but considering that DateTime is what I need to make sure that I'm after in the body of the handler this is the best I can come up with.

private static void handler()
{
    // because I can handle a few second delay,
    // a delay of 1 second is acceptible to me
    while(DateTime.Now > _waitForThisDateTime) Thread.Sleep(1000);

    //Handler body here
}

Comments from @PaulF and @AlexeiLevenkov note that trying to have an accurate time with respect to the inaccurate DateTime is flawed, so I don't think there is a better answer. The "fix" in the long term will be for me to change the existing code altogether to not have this requirement of being after a given DateTime!

As an aside, Timer seems to get less accurate the longer the TimeSpan that is passed to it. Our time span is on the order of 1 day, so the errors I'm seeing are larger than in the demo I give in my OP.

Frank Bryce
  • 8,076
  • 4
  • 38
  • 56