Wednesday, July 27, 2011

Event handling in c#


Instead, you will need to write your own timer object using multi-threading in C#. In this article I describe just how to write your own Timer for your Console Application.




First you need to build your own timer class object. To start, we can do something like this:
    class Timer
    {
        // Delegates
        public delegate void Tick();

        // Properties
        public int Interval;
        public Tick OnTimerTick;

        // Private Data
        Thread _timerThread;
        volatile bool _bStop;
    }

Next you want to implement an event loop for the timer. This code will run on the timer's thread, not the main thread. Here is how you'd write one:

    public void Run()
    {
        while (!_bStop)
        {
            // Sleep for the timer interval
            Thread.Sleep(Interval);
            // Then fire the tick event
            OnTimerTick();
        }   
    }

A Timer has a Start & Stop methods. These methods run on the main thread, and control the timer's operation. The above timer event loop however runs on a separate worker thread, which is created in the Start method implementation as follows:

    public Thread Start()
    {
        _bStop = false;
        _timerThread = newThread(newThreadStart(Run));
        _timerThread.IsBackground = true;
        _timerThread.Start();
        return _timerThread;
    }
Now to stop the Timer, we'll need to set the volatile boolean in the Timer data members to false. The Stop Method is invoked from the main thread. The value of the volatile member is then checked each time in the event loop of the worker thread (as seen above). Here is how to implement the Stop method for the timer:
    public void Stop()
    {
        // Request the loop to stop
        _bStop=true;
    }
Notice that the stop method would only put a request to stop the timer, but won't kill the thread. If the timer interval is short, that isn't much of a problem, but if the timer interval is long, say 5 minutes, it might take the whole 5 minutes before the timer checks the above volatile member and decides to stop the event loop. To fix this, there are 2 options, first is to simply kill the worker thread in the Stop implementation (remember the Stop method is invoked on the main thread), as follows:
    public void Stop()
    {
        // Request the loop to stop
        _bStop=true;
        _timerThread.Join(1000);
          _timerThread.Abort();
    }
A better way however is to sleep intermittently in the event loop and check the volatile member more frequently:
    public void Run()
    {
        while (true)
        {
            // Sleep for the timer interval
            SleepIntermittently(Interval);
            // Then fire the tick event
            OnTimerTick();
        }
    }
Now you can just implement the Stop method as before. Here is the implementation of the SleepIntermittently method:
    public void SleepIntermittently(int totalTime)
    {
        int sleptTime = 0;
        int intermittentSleepIncrement = 10;
        while (!_bStop && sleptTime < totalTime)
        {
            Thread.Sleep(intermittentSleepIncrement);
            sleptTime += intermittentSleepIncrement;
        }
    }
Finally here is a test application for our Console timer:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace TimerConsoleApp
{
    class Program
    {
        public static void timerTick()
        {
            Console.WriteLine("[W] Timer Ticked!");
        }

        static void Main (string[] args)
        {
            Timer timer = newTimer();
            timer.Interval=500;
            timer.OnTimerTick += timerTick;
            Thread timerThread = timer.Start();

            for (int i = 0; i < 10; i++)
            {
                if (i > 5)
                {
                    Console.WriteLine("[M] Timer is Stopped! " +DateTime.Now.ToLongTimeString());
                }
                 else
                {
                    Console.WriteLine("[M] Timer is Active! " +DateTime.Now.ToLongTimeString());
                }

                if (i == 5)
                {
                    Console.WriteLine("[M] Stopping the timer...");
                    timer.Stop();
                }

                // Do lengthy main thread processing here
                ///
                Thread.Sleep(5000);
            }
        }
    }
}
And now the timer is ready for use.
Happy Programming!

No comments:

Post a Comment

Your comment is pending for approval

AngularJS Basics - Part 1

                                                                  AngularJS What is AngularJS ·          Framework by googl...