Thursday, September 06, 2007

TIMING YOUR EVENTS: The .NET Party

It is a popular saying in Yoruba language (permit me to use it) that “enikan ki I bu sango l’erun” (meaning no one invokes the god of thunder in the dry season). Whatever this means, timing is crucial to the menace (or benefits if any) of the invocation of the god of Thunder. Even when all recipes are available, it is important it be raining season for the effects to be significant. So are the timer controls in .NET. Did I hear you say “timer controls”?

When I started out being a .Net developer, sequel to my background as a VB developer, I deemed the timer control as “unified”. By this unification, I suppose that in whatever scenario where one needs to invoke some sequence of operations at intervals, the “visual” timer control would be sufficient. Damn!!! I was wrong.

There isn’t anything like “visual” timer control. I am only trying to insinuate an instance of the “System.Windows.Form.Timer” class; which is the only visible timer control in .Net (at least in the toolbox). By this visibility, a lot of naïve (did I use that word?) developers like me thought that was all .Net has got to offer about timing your events until the last time it failed. This time, I was building a Windows Service.

The Motivation:

I was required by a superior to develop an Application such that:

· Requires little or NO user interactions;

· Runs in the background of the OS;

· Performs a set of routines at specified intervals; basically every morning, every Monday and every start of a new month;

My Analysis:

With the set of requirements above, I needed not to be told any further that I needed to build a Windows Service App that keeps track of time change. In order to track time changes, I know a timer control is a definite option. The System.Windows.Form.Timer Class provides the nearest timer to use, so I delved into development. Though, I was not cautious of the fact that I was invoking the wrong Timer instance.

The following were what I did:

· Dragged and dropped the System.Window.Forms.Timer Timer control on the Windows service interface;

· Set the enabled property of the timer control to True;

· Set interval to 5000 (ms);

· Wrote loads of logics in the Tick method of the Timer control;

· Built it (no error was returned);

· Deployed the application but the logics in the Tick method of the Timer control never got invoked;

· Then my frustration, motivation, research, discovery and finally, this article.

My Flaw:

Just as it is healthy to read the prescription inscribed at the back of tablets pack before usage, it is also highly placed as important to read the documentation of every control provided in any development environment before applying them to use.

The System.Windows.Forms.Timer Timer control implements a timer that raises an event at user-defined interval. This timer is optimized for use in Windows Forms applications and MUST be used in a Window. This is the vendor’s (Microsoft) recommendation, which I skipped and eventually ran into a ditch. Good for me though. I read the prescription after taking the dosage; this time, overly.

My Research:

After examining why my Tick event wasn’t getting invoked, I discovered that I wasn’t meant to use a control that was meant strictly for a Windows Form in the Development of a Windows Service. My conviction of using a Timer control persisted given the requirements like my superior.

I found out that .Net provides three types of the Timer Control. Each optimized for there various environments.

· System.Windows.Forms.Timer Class instance

· System.Timers.Timer class instance

· System.Threading.Timer class instance.

System.Windows.Forms.Timer Class instance

This implements a timer that raises an event at user-defined intervals. This timer is optimized for use in Windows Forms applications and must be used in a window.

This Windows timer is designed for a single-threaded environment where UI threads are used to perform processing. It requires that the user code have a UI message pump available and always operate from the same thread, or marshal the call onto another thread.

When using this timer, use the Tick event to perform a polling operation or to display a splash screen for a specified amount of time. Whenever the Enabled property is set to true and the Interval property is greater than zero, the Tick event is raised at intervals based on the Interval property setting.

This class provides methods to set the interval, and to start and stop the timer

Example:

[C#]

public class Class1

{

static System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();

static int alarmCounter = 1;

static bool exitFlag = false;

// This is the method to run when the timer is raised.

private static void TimerEventProcessor(Object myObject, EventArgs myEventArgs)

{

myTimer.Stop();

// Displays a message box asking whether to continue running the timer.

if(MessageBox.Show("Continue running?", "Count is: " + alarmCounter, MessageBoxButtons.YesNo) == DialogResult.Yes)

{

// Restarts the timer and increments the counter.

alarmCounter +=1;

myTimer.Enabled = true;

}

else

{

// Stops the timer.

exitFlag = true;

}

}

public static int Main()

{

/* Adds the event and the event handler for the method that will process the timer event to the timer. */

myTimer.Tick += new EventHandler(TimerEventProcessor);

// Sets the timer interval to 5 seconds.

myTimer.Interval = 5000;

myTimer.Start();

// Runs the timer, and raises the event.

while(exitFlag == false)

{

// Processes all the events in the queue.

Application.DoEvents();

}

return 0;

}

}

System.Timers.Timer class instance

This Timer component is a server-based timer, which allows you to specify a recurring interval at which the Elapsed event is raised in your application. You can then handle this event to provide regular processing. For example, suppose you have a critical server that must be kept running 24 hours a day, 7 days a week. You could create a service that uses a Timer to periodically check the server and ensure that the system is up and running. If the system is not responding, the service could attempt to restart the server or notify an administrator.

The server-based Timer is designed for use with worker threads in a multithreaded environment. Server timers can move among threads to handle the raised Elapsed event, resulting in more accuracy than Windows timers in raising the event on time

Note The event-handling method might be called even after the Stop method is called. The event-handling method might run on one thread at the same time that a call to the Stop method runs on another thread. This might result in the Elapsed event being raised even after the Stop method is called. To prevent this, use the SignalTime property to compare the time the event was raised to the time the Stop method was called. If the event was raised after the Stop method was called, do not process the event.

The Timer component raises the Elapsed event, based on the value of the Interval property. You can handle this event to perform the processing you need. For example, suppose that you have an online sales application that continuously posts sales orders to a database. The service that compiles the instructions for shipping operates on a batch of orders rather than processing each order individually. You could use a Timer to start the batch processing every 30 minutes.

Note When AutoReset is set to false, the Timer raises the Elapsed event only once, after the first Interval has elapsed. To keep raising the Elapsed event on the Interval, set AutoReset to true.

The Timer is not visible at run time.

Example

[C#]

public class Timer1

{

public static void Main()

{

System.Timers.Timer aTimer = new System.Timers.Timer();

aTimer.Elapsed+=new ElapsedEventHandler(OnTimedEvent);

// Set the Interval to 5 seconds.

aTimer.Interval=5000;

aTimer.Enabled=true;

Console.WriteLine("Press \'q\' to quit the sample."); while(Console.Read()!='q');

}

// Specify what you want to happen when the Elapsed event is raised.

private static void OnTimedEvent(object source, ElapsedEventArgs e)

{

Console.WriteLine("Hello World!");

}

}

System.Threading.Timer class instance

Use a TimerCallback delegate to specify the method you want the Timer to execute. The timer delegate is specified when the timer is constructed, and cannot be changed. The method does not execute on the thread that created the timer; it executes on a ThreadPool thread supplied by the system.

When you create a timer, you can specify an amount of time to wait before the first execution of the method (due time), and an amount of time to wait between subsequent executions (period). You can change these values, or disable the timer, using the Change method.

NoteNote:

As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.

When a timer is no longer needed, use the Dispose method to free the resources held by the timer. To receive a signal when the timer is disposed, use the Dispose(WaitHandle) method overload that takes a WaitHandle. The WaitHandle is signaled when the timer has been disposed.

The callback method executed by the timer should be reentrant, because it is called on ThreadPool threads. The callback can be executed simultaneously on two thread pool threads if the timer interval is less than the time required to execute the callback, or if all thread pool threads are in use and the callback is queued multiple times.

NoteNote:

System.Threading.Timer is a simple, lightweight timer that uses callback methods and is served by thread pool threads. It is not recommended for use with Windows Forms, because its callbacks do not occur on the user interface thread. System.Windows.Forms.Timer is a better choice for use with Windows Forms. For server-based timer functionality, you might consider using System.Timers.Timer, which raises events and has additional features.


C#

using System;

using System.Threading;

class TimerExample

{

static void Main()

{

AutoResetEvent autoEvent = new AutoResetEvent(false);

StatusChecker statusChecker = new StatusChecker(10);

// Create the delegate that invokes methods for the timer.

TimerCallback timerDelegate =

new TimerCallback(statusChecker.CheckStatus);

// Create a timer that signals the delegate to invoke

// CheckStatus after one second, and every 1/4 second

// thereafter.

Console.WriteLine("{0} Creating timer.\n",

DateTime.Now.ToString("h:mm:ss.fff"));

Timer stateTimer =

new Timer(timerDelegate, autoEvent, 1000, 250);

// When autoEvent signals, change the period to every

// 1/2 second.

autoEvent.WaitOne(5000, false);

stateTimer.Change(0, 500);

Console.WriteLine("\nChanging period.\n");

// When autoEvent signals the second time, dispose of

// the timer.

autoEvent.WaitOne(5000, false);

stateTimer.Dispose();

Console.WriteLine("\nDestroying timer.");

}

}

class StatusChecker

{

int invokeCount, maxCount;

public StatusChecker(int count)

{

invokeCount = 0;

maxCount = count;

}

// This method is called by the timer delegate.

public void CheckStatus(Object stateInfo)

{

AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;

Console.WriteLine("{0} Checking status {1,2}.",

DateTime.Now.ToString("h:mm:ss.fff"),

(++invokeCount).ToString());

if(invokeCount == maxCount)

{

// Reset the counter and signal Main.

invokeCount = 0;

autoEvent.Set();

}

}

}


1 comment:

Unknown said...

This sounds like a lifesaver but yet to try it out.Once a Again bro you've done it Again.