Thursday 9 April 2009

Multi-Threading (.Net) :- System.Timer.Time class

Dotnet provides a server-based timer ( and is different from System.Windows.Forms.Timer and System.Threading.Timer ), allow us to specify a recurring interval at which an event will be raised in our application(or Easy way of executing a task at specified interval).


Below example (c# console application) shows how to create a Timer ,execute a task at specified interval and how to stop Timer gracefully.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Timers;

namespace BackgroundThread_Terminate
{

class Program
{
static void Main(string[] args)
{
using (TimerClass_example1 timerSample = new TimerClass_example1())
{

Console.ReadLine();
}

Console.ReadLine();
}
}


public class TimerClass_example1:IDisposable
{
System.Timers.Timer timer;

long _stopTimer = 0; // 0 for start , 1 for stop

ManualResetEvent manualReset = new ManualResetEvent(false);

public TimerClass_example1()
{
timer = new System.Timers.Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}

//call back function excuted on a threadpool thread.
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
//always use try catch in callback
try
{
//gracefully stop timer
if(Interlocked.Read(ref _stopTimer) == 1 )
{
timer.Stop();
//signal the thread which is waiting.
manualReset.Set();

return;
}

Console.WriteLine(string.Format("Executed callback at {0}. Threadpool Thread ID:- {1}", DateTime.Now.ToString(), Thread.CurrentThread.ManagedThreadId));

//Note #1:- Uncomment below the and note the ThreadID's printed
//Thread.Sleep(2000); //[ Reason for printing different Thread is :- The Elapsed event is raised on a ThreadPool thread. If processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. Thus, the event handler should be reentrant.]
}
catch (Exception ex)
{
//log exception and you can stop excuting Timer.
}
}


public void Dispose()
{
StopAndDisposeTimer();
GC.SuppressFinalize(this);

Console.WriteLine("Timer has been disposed");
}

private void StopAndDisposeTimer()
{
Interlocked.Exchange(ref _stopTimer, 1);

//wait 5 secs for signal
if (!manualReset.WaitOne(5000, false))
{
Console.WriteLine("Timer is not stopped gracefully.");
}

timer.Dispose();
}

~TimerClass_example1()
{
Dispose();
}
}
}