A Simple Timer

1 reply [Last post]
magius96's picture
Offline
Last seen: 14 weeks 1 day ago
Joined: 04/13/2009
Posts:

Today I found out that System.Timers.Timer is buggy and doesn't work when used in a windows service application. Microsoft suggest we use the System.Threading.Timer object instead.

http://support.microsoft.com/kb/842793
I looked into it, and found that to use the System.Threading.Timer object, you have to supply it with a delegate to a static method that it can call when the timer event is triggered. In my application, that means I would have to change virtually all my methods and variables to being static, not something that I wanted to do. So instead I wrote my own timer, using the System.Threading methods. This is a fairly simple timer system:


using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        AutoResetEvent arv = new AutoResetEvent(false);
        bool Stop = false;
        int called = 0;

        while (Stop == false)
        {
            arv.WaitOne(5000);
            called++;
            Console.WriteLine(string.Format("Waited: {0}", called));
            if (called == 10)
                Stop = true;
        }
    }
}

There's one thing to keep in mind here; this effectively locks up the current thread until the elapsed time has passed. In the above example, the elapsed time is 5 seconds (5000 milliseconds). It shouldn't take very much to build this concept into an instantiable class that uses a seperate processing thread to prevent locking up your application until the elapsed time, and I'd highly advise that you do so.

Today's discovery of this bug in a Microsoft system class only serves to validate my belief that you should always write your own methods if possible, instead of using methods someone else wrote.

----------------------------------------------------------------------------------------------------
"Coding your life, Compiling your dreams, and crashing your future."
Compilr - C# and VB.NET Advisor

magius96's picture
Offline
Last seen: 14 weeks 1 day ago
Joined: 04/13/2009
Posts:
Custom Timer Class


using System.IO;
using System.Threading;

namespace Utilities
{
    public delegate void TimerElapsed();

    ///
    /// Custom timer class since System.Timers.Timer is buggy.
    /// If something goes wrong and this locks your application, create a file named
    /// timer.kill in the same directory and this process will stop itself.
    ///
    public class Timer
    {
        public event TimerElapsed Elapsed;

        Thread TimerThread;
        bool Stopping;
        int TimerSpan;

        public void Start(int Milliseconds)
        {
            TimerSpan = Milliseconds;
            TimerThread = new Thread(TimerPulse);
            TimerThread.Start();
        }

        public void Start(int Hours, int Minutes, int Seconds)
        {
            int Total = 0;
            Total += Seconds * 1000;
            Total += Minutes * 60 * 1000;
            Total += Hours * (60 * 60 * 1000);
            Start(Total);
        }

        private void TimerPulse()
        {
            AutoResetEvent areEvent = new AutoResetEvent(false);

            while (Stopping == false && File.Exists("timer.kill") == false)
            {
                areEvent.WaitOne(TimerSpan);
                Elapsed();
            }
        }

        public void Stop()
        {
            Stopping = true;
            TimerThread.Abort();
        }
    }
}

And an example usage:


Utilities.Timer Pulse = new Utilities.Timer();
Pulse.Elapsed += new TimerElapsed(Pulse_Elapsed);
Pulse.Start(60000);

protected void Pulse_Elapsed()
{
    // Do your timed code here.
}

Ok, so now the custom timer is built into a class that uses threading to seperate the loop from the application. This allows the timer to run without locking up your application. Since you can't easily communicate between process threads, this sets up an event to be raised when the timer goes off.

Also note that you can stop the timer by creating a "timer.kill" file in the directory where the application runs, as well as call the Stop() method.

As you can see, a few slightly advanced tricks were used to pull this timer off, application threading, delegates, and custom events. For more information about these topics, take a look at the appropriate tutorial by me, located on www.compilr.com

----------------------------------------------------------------------------------------------------
"Coding your life, Compiling your dreams, and crashing your future."
Compilr - C# and VB.NET Advisor