2

I'm using Threading.Timer, like:

new System.Threading.Timer(
            new System.Threading.TimerCallback(x=>
                file.Write(DateTime.Now.ToString())
            ), null, 0, 600000);

And, for example it starts at 11:00:00, then i get in file:

11:00:00
11:10:00
11:20:00
...
12:10:00
12:19:59
12:29:59

Why? from some time it begins to do such things? I've tried other timers, like Timers.Timer, and winforms Timer, the same situation. It's depressing me.

EDIT: Solution with accuratetimer which posted in the thread, didnt help. What about win32 multimedia timer, can it help?

Jack Malkovich
  • 786
  • 13
  • 33
  • see if this See http://stackoverflow.com/questions/897108/how-reliable-are-net-timers and this http://stackoverflow.com/questions/5015255/reliable-alternative-to-timer-in-net-framework helps. – gideon Apr 07 '11 at 07:33
  • Also see: [Why are .NET timers limited to 15 ms resolution?](http://stackoverflow.com/questions/3744032/why-are-net-timers-limited-to-15-ms-resolution) – Cody Gray - on strike Apr 07 '11 at 08:01

4 Answers4

3

because the timer mechanism isn't ideal, portion of time is needed each time file.Write(DateTime.Now.ToString() is executed. thus in due time you have a delay in one second, try leaving it for an hour and I guess you'll have 3 second delay then.

I'm not sure whenever System.Threading.Timer can compensate this by tracking execution time, u should check the manual for options

Take a look at System.Timers.Timer class also.

Also try using this

class Timer
{
    private Stopwatch sw;
    private Thread executor;
    private long interval;

    public void Start(int intervalInMilliseconds)
    {
        interval = intervalInMilliseconds;
        sw = new Stopwatch();
        executor = new Thread(Run);
        executor.Start();
    }

    public void Run()
    {
        while (true)
        {
            sw.Start();
            Execute();
            sw.Stop();
            Thread.Sleep((int)(interval - sw.ElapsedMilliseconds));
            sw.Reset();
        }
    }


    public void Execute()
    {
        // Do your code here
    }

}
Troydm
  • 2,642
  • 3
  • 24
  • 35
  • yep. i got delay for 15 second, then i leaved it for one day. how can i make it work properly? nobody got this situation? – Jack Malkovich Apr 07 '11 at 07:18
  • @Jack: It's working properly now. See my answer for details. Switching to a different timer implementation (there are 3 provided by the .NET Framework) is not going to solve this problem. It occurs at a lower level in Windows. No one considers a few milliseconds here and there to be a problem. – Cody Gray - on strike Apr 07 '11 at 07:46
  • >while(true), not best solution, i think – Jack Malkovich Apr 07 '11 at 07:53
  • Right, `while(true)` works because it consumes 100% of your CPU time. If you're willing to completely abandon responsiveness, it becomes possible to attain greater accuracy. That doesn't make it a good idea, though. Expecting Windows to report information with a greater than 15 ms accuracy is barking up the wrong tree. You need to switch to a real-time operating system if this is that important to you. – Cody Gray - on strike Apr 07 '11 at 08:01
  • thats make me cry. okay. trying to use this solution. – Jack Malkovich Apr 07 '11 at 08:08
  • @Cody Gray: You can actually set the timer period to much lower values, down to 0.997 ms (on my computer) from the default 15.625 ms, at the cost of higher CPU load for all non-idle threads. See also my answer below. – Alan Apr 07 '11 at 08:15
  • @Alan: You're talking about the multimedia timer, which is a different thing. There are also lots of other important caveats, like the one you mentioned: high CPU load, which quickly drains the batteries on portable computers (up to 25% or more increase) and costs more in energy. Additionally, it relies on hardware support. Not all machines have high-resolution timers built in. You're not simply increasing the resolution of the standard timer. It's implemented in a completely different way "under the hood". It, also, is not *guaranteed*; it's subject to being pre-empted like any other timer. – Cody Gray - on strike Apr 07 '11 at 08:26
  • while(true) in this example doesn't consume high CPU load since it's cycle is executed only during method execution that happens only during the timer action execution, then it goes to sleep by executing Thread.sleep(interval - timeItSpentExecutingActionInMillis) so that it's recurring self correcting timer – Troydm Apr 07 '11 at 10:19
  • @Cody Gray: Yes, you are right, the MM timer is different. Alas, my comment was easy to misunderstand (but my answer isn't IMHO). BTW, with my last project I ended up abandoning the MM timer altogether and implementing a quantizing wrapper around a System.Threading.Timer set to an interval of 15 ms - statistically, this can approach any desired average ticks per second almost perfectly (in the long run), with no CPU load (a plus) and slightly uneven intervals (a minus, of course). – Alan Apr 07 '11 at 20:32
0

Yes, the timer is subject to being pre-empted by other important tasks. Nowhere is it guaranteed that the timer will execute precisely on the interval you set. It's only an approximate interval because Windows is a multitasking operating system. If the computer is busy doing something else, it won't be able to service your timer message(s) immediately. So the messages get put into a queue, which allows them to be postponed until it can do so.

That's why you should always check for a time value that is equal to or greater than the time you expect. It's guaranteed that less time will never have elapsed, but it's not guaranteed that more time won't have elapsed. The other timer implementations are no different.

The documentation for the timer provided by the Windows API goes into more detail:

An application uses a timer to schedule an event for a window after a specified time has elapsed. Each time the specified interval (or time-out value) for a timer elapses, the system notifies the window associated with the timer. Because a timer's accuracy depends on the system clock rate and how often the application retrieves messages from the message queue, the time-out value is only approximate.

Windows simply doesn't provide timing mechanisms this precise. In 99 out of 100 cases, it's simply not relevant. For that 1 in 100 case, you need a real-time operating system.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Ok. So where is no libraries, which can help me to prove situation? which will chech the time for me& – Jack Malkovich Apr 07 '11 at 07:48
  • @Jack: You're already using something that checks the time for you. It's called a timer. The problem is that it's not guaranteed to have accuracy down to the millisecond. Some "drift" should be expected. The data you've shown shows *at most* a difference of a single second. The real difference is probably significantly less, your code is just rounding off to the nearest whole second. – Cody Gray - on strike Apr 07 '11 at 07:53
  • sorry. i simply want to write into files proper times. i can't do it?:( – Jack Malkovich Apr 07 '11 at 07:55
  • @Jack: With **sub-millisecond** accuracy? No, you can't do it. Not with a standard timer. The other solutions are all overkill, definitely not recommended for this application. – Cody Gray - on strike Apr 07 '11 at 07:58
0

Here is more accurate timer for you:

class AccurateTimer
{
    private TimerCallback _Callback;
    private TimeSpan _Period;
    private bool _IsWorking = true;

    public void Stop()
    {
        _IsWorking = false;
    }

    public AccurateTimer(TimerCallback callback, int period)
    {
        _Period = TimeSpan.FromMilliseconds(period);
        _Callback = callback;

        new Thread(ThreadMethod).Start();
    }

    private void ThreadMethod()
    {
        while (_IsWorking)
        {
            var start = DateTime.Now;
            _Callback.BeginInvoke(null, null, null);
            Thread.Sleep(_Period - (DateTime.Now - start));
        }
    }
}

Usage:

class Program
{
    static void Main(string[] args)
    {
        var timer = new AccurateTimer(x => Console.WriteLine(DateTime.Now.ToString("h:mm:ss.fff")), 3000);
        Console.ReadKey();
        timer.Stop();
    }
}

Output:

11:44:46.987
11:44:49.985
11:44:52.985
11:44:55.985
11:44:58.985
11:45:01.985

System.Threading.Timer:

class Program
{
    static void Main(string[] args)
    {
        new System.Threading.Timer(x => Console.WriteLine(DateTime.Now.ToString("h:mm:ss.fff")), null, 0, 3000);
        Console.ReadKey();
    }
}

Output:

11:50:22.042
11:50:25.040
11:50:28.051
11:50:31.065
11:50:34.073
11:50:37.083
bniwredyc
  • 8,649
  • 1
  • 39
  • 52
0

If you are willing to sacrifice some CPU time, you can use the multimedia timer (check this out for a sample C# implementation that I used as a basis for my own component).

You will find that its actual accuracy is up to 1 ms, unlike any other .NET timers or custom solutions that will always necessarily rely on the default 15.625 ms Windows timer.

Caveats: (1) I have only been able to successfully create up to 2 instances of this timer in the same AppDomain - with more instances, some of them did not raise the tick events at all (or after a short while), and (2) do monitor the increased CPU load and decide whether the extra accuracy is worth it.

Alan
  • 6,501
  • 1
  • 28
  • 24