When you use a Timer or a Thread that will just run for the entire lifetime of the program do you need to keep a reference to them to prevent them from being garbage collected?
Please put aside the fact that the below program could have timer as a static variable in the class, this is just a toy example to show the issue.
public class Program
{
static void Main(string[] args)
{
CreateTimer();
Console.ReadLine();
}
private static void CreateTimer()
{
var program = new Program();
var timer = new Timer();
timer.Elapsed += program.TimerElapsed;
timer.Interval = 30000;
timer.AutoReset = false;
timer.Enabled = true;
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
var timerCast = (Timer)sender;
Console.WriteLine("Timer fired at in thread {0}", GetCurrentThreadId());
timerCast.Enabled = true;
}
~Program()
{
Console.WriteLine("Program Finalized");
}
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
}
Could the timer get collected in that above example? I ran it for a while and I never got a exception nor a message saying ~Program() was called.
UPDATE: I found out from this question (thanks sethcran) that threads are tracked by the CLR, but I still would like an answer about Timers.
This is only a problem with the System.Threading.Timer class if you don't otherwise store a reference to it somewhere. It has several constructor overloads, the ones that take the state object are important. The CLR pays attention to that state object. As long as it is referenced somewhere, the CLR keeps the timer in its timer queue and the timer object won't get garbage collected. Most programmers will not use that state object, the MSDN article certainly doesn't explain its role.
System.Timers.Timer is a wrapper for the System.Threading.Timer class, making it easier to use. In particular, it will use that state object and keep a reference to it as long as the timer is enabled.
Note that in your case, the timer's Enabled property is false when it enters your Elapsed event handler because you have AutoReset = false. So the timer is eligible for collection as soon as it enters your event handler. But you stay out of trouble by referencing the sender argument, required to set Enabled back to true. Which makes the jitter report the reference so you don't have a problem.
Do be careful with the Elapsed event handler. Any exception thrown inside that method will be swallowed without a diagnostic. Which also means that you won't set Enabled back to true. You must use try/catch to do something reasonable. If you are not going to intentionally end your program, at a minimum you'll need to let your main program know that something isn't working anymore. Putting Enabled = true in a finally clause can avoid getting the timer garbage collected, but at the risk of having your program throw exceptions over and over again.
Let's carry out an experiment:
private static void UnderTest() {
// Timer is a local varibale; its callback is local as well
System.Threading.Timer timer = new System.Threading.Timer(
(s) => { MessageBox.Show("Timer!"); },
null,
1000,
1000);
}
...
// Let's perform Garbage Colelction manually:
// we don't want any surprises
// (e.g. system starting collection in the middle of UnderTest() execution)
GC.Collect(2, GCCollectionMode.Forced);
UnderTest();
// To delay garbage collection
// Thread.Sleep(1500);
// To perform Garbage Collection
// GC.Collect(2, GCCollectionMode.Forced);
So far
if we keep commented both Thread.Sleep(1500); and GC.Collect(2, GCCollectionMode.Forced); we'll see message boxes appear: the timer is working
if we uncomment GC.Collect(2, GCCollectionMode.Forced); we'll see nothing: the timer starts then it is collected
if we uncomment both Thread.Sleep(1500); and GC.Collect(2, GCCollectionMode.Forced); we'll see a single message box: the timer starts, goes off a single message box and then the timer is collected
So System.Threading.Timers are collected as any other object instances.
Add this code to a program and run it. You'll see that the timer is NOT collected.
private void DoStuff()
{
CreateTimer();
Console.WriteLine("Timer started");
int count = 0;
for (int x = 0; x < 1000000; ++x)
{
string s = new string("just trying to exercise the garbage collector".Reverse().ToArray());
count += s.Length;
}
Console.WriteLine(count);
Console.Write("Press Enter when done:");
Console.ReadLine();
}
private void Ticktock(object s, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("Ticktock");
}
private void CreateTimer()
{
System.Timers.Timer t = new System.Timers.Timer(); // Timer(Ticktock, null, 1000, 1000);
t.Elapsed += Ticktock;
t.Interval = 1000;
t.AutoReset = true;
t.Enabled = true;
}
So the answer to your question appears to be that the timer is not eligible for collection and will not be collected if you don't maintain a reference to it.
It's interesting to note that if you run the same test with System.Threading.Timer, you'll find that the timer is collected.
Related
I have a Windows Service which connects to an external device (micro controller) to get data and save it to database. The external device does not support callback feature, that's why the service should ask for the data frequently.
What I did so far: I created a service with a timer which ticks frequently, based on configuration.
Here, I have two problems:
Sometimes the data very big, and before collecting and saving that data, the timer is restarting based on configuration. In this case, I'm losing the data.
If I configure the timer for longer period, I'm losing monitoring which data should be monitored immediately after collect.
I've read other related questions like doing a recursive call in the background service, etc. But I don't have exit condition for recursive call. Application should continue working even after some exception occurs.
Here is my code:
public partial class DataManagerService : ServiceBase
{
public DataManagerService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
timer = new System.Timers.Timer(1000);
timer.Elapsed += new System.Timers.ElapsedEventHandler(OnElapsedTime);
timer.Enabled = true;
}
private void OnElapsedTime(object source, System.Timers.ElapsedEventArgs e)
{
GetRecords();
}
protected override void OnStop()
{
// clean up
}
}
PS: I'm using .NET Framework 4.6.1 and Visual Studio 2017 Community edition
The System.Timers.Timer.Stop documentation contains a (non-trivial) example of how to accomplish this using two Timer instances. At each interval, a separate control Thread leverages:
a static currentTimer field to select the correct Timer instance
the System.Threading.Interlocked.CompareExchange static method to prevent overlapping Elapsed events.
Because I see a little ambiguity in your requirement, let me call out Microsoft's note about the use case for this approach versus System.Threading.Monitor:
If it were necessary to execute every event, the Monitor class would be a better way to synchronize the events.
From Microsoft docs System.Timers.Timer.Stop examples
The following code example shows one way to prevent the thread that calls the Stop method from continuing until a currently executing Elapsed event ends, and also to prevent two Elapsed events from executing the event handler at the same time (often referred to as reentrancy).
The example executes 100 test runs. Each time the test is run, the timer is started with an interval of 150 milliseconds. The event handler uses the Thread.Sleep method to simulate a task that randomly varies in length from 50 to 200 milliseconds. The test method also starts a control thread that waits for a second and then stops the timer. If an event is being handled when the control thread stops the timer, the control thread must wait until the event is finished before proceeding.
The Interlocked.CompareExchange(Int32, Int32, Int32) method overload is used to avoid reentrancy and to prevent the control thread from continuing until an executing event ends. The event handler uses the CompareExchange(Int32, Int32, Int32) method to set a control variable to 1, but only if the value is currently zero. This is an atomic operation. If the return value is zero, the control variable has been set to 1 and the event handler proceeds. If the return value is non-zero, the event is simply discarded to avoid reentrancy. (If it were necessary to execute every event, the Monitor class would be a better way to synchronize the events.) When the event handler ends, it sets the control variable back to zero. The example records the total number of events that executed, that were discarded because of reentrancy, and that occurred after the Stop method was called.
The control thread uses the CompareExchange(Int32, Int32, Int32) method to set the control variable to -1 (minus one), but only if the value is currently zero. If the atomic operation returns non-zero, an event is currently executing. The control thread waits and tries again. The example records the number of times the control thread had to wait for an event to finish.
using System;
using System.Timers;
using System.Threading;
public class Test
{
// Change these values to control the behavior of the program.
private static int testRuns = 100;
// Times are given in milliseconds:
private static int testRunsFor = 500;
private static int timerIntervalBase = 100;
private static int timerIntervalDelta = 20;
// Timers.
private static System.Timers.Timer Timer1 = new System.Timers.Timer();
private static System.Timers.Timer Timer2 = new System.Timers.Timer();
private static System.Timers.Timer currentTimer = null;
private static Random rand = new Random();
// This is the synchronization point that prevents events
// from running concurrently, and prevents the main thread
// from executing code after the Stop method until any
// event handlers are done executing.
private static int syncPoint = 0;
// Count the number of times the event handler is called,
// is executed, is skipped, or is called after Stop.
private static int numEvents = 0;
private static int numExecuted = 0;
private static int numSkipped = 0;
private static int numLate = 0;
// Count the number of times the thread that calls Stop
// has to wait for an Elapsed event to finish.
private static int numWaits = 0;
[MTAThread]
public static void Main()
{
Timer1.Elapsed += new ElapsedEventHandler(Timer1_ElapsedEventHandler);
Timer2.Elapsed += new ElapsedEventHandler(Timer2_ElapsedEventHandler);
Console.WriteLine();
for(int i = 1; i <= testRuns; i++)
{
TestRun();
Console.Write("\rTest {0}/{1} ", i, testRuns);
}
Console.WriteLine("{0} test runs completed.", testRuns);
Console.WriteLine("{0} events were raised.", numEvents);
Console.WriteLine("{0} events executed.", numExecuted);
Console.WriteLine("{0} events were skipped for concurrency.", numSkipped);
Console.WriteLine("{0} events were skipped because they were late.", numLate);
Console.WriteLine("Control thread waited {0} times for an event to complete.", numWaits);
}
public static void TestRun()
{
// Set syncPoint to zero before starting the test
// run.
syncPoint = 0;
// Test runs alternate between Timer1 and Timer2, to avoid
// race conditions between tests, or with very late events.
if (currentTimer == Timer1)
currentTimer = Timer2;
else
currentTimer = Timer1;
currentTimer.Interval = timerIntervalBase
- timerIntervalDelta + rand.Next(timerIntervalDelta * 2);
currentTimer.Enabled = true;
// Start the control thread that shuts off the timer.
Thread t = new Thread(ControlThreadProc);
t.Start();
// Wait until the control thread is done before proceeding.
// This keeps the test runs from overlapping.
t.Join();
}
private static void ControlThreadProc()
{
// Allow the timer to run for a period of time, and then
// stop it.
Thread.Sleep(testRunsFor);
currentTimer.Stop();
// The 'counted' flag ensures that if this thread has
// to wait for an event to finish, the wait only gets
// counted once.
bool counted = false;
// Ensure that if an event is currently executing,
// no further processing is done on this thread until
// the event handler is finished. This is accomplished
// by using CompareExchange to place -1 in syncPoint,
// but only if syncPoint is currently zero (specified
// by the third parameter of CompareExchange).
// CompareExchange returns the original value that was
// in syncPoint. If it was not zero, then there's an
// event handler running, and it is necessary to try
// again.
while (Interlocked.CompareExchange(ref syncPoint, -1, 0) != 0)
{
// Give up the rest of this thread's current time
// slice. This is a naive algorithm for yielding.
Thread.Sleep(1);
// Tally a wait, but don't count multiple calls to
// Thread.Sleep.
if (!counted)
{
numWaits += 1;
counted = true;
}
}
// Any processing done after this point does not conflict
// with timer events. This is the purpose of the call to
// CompareExchange. If the processing done here would not
// cause a problem when run concurrently with timer events,
// then there is no need for the extra synchronization.
}
// Event-handling methods for the Elapsed events of the two
// timers.
//
private static void Timer1_ElapsedEventHandler(object sender,
ElapsedEventArgs e)
{
HandleElapsed(sender, e);
}
private static void Timer2_ElapsedEventHandler(object sender,
ElapsedEventArgs e)
{
HandleElapsed(sender, e);
}
private static void HandleElapsed(object sender, ElapsedEventArgs e)
{
numEvents += 1;
// This example assumes that overlapping events can be
// discarded. That is, if an Elapsed event is raised before
// the previous event is finished processing, the second
// event is ignored.
//
// CompareExchange is used to take control of syncPoint,
// and to determine whether the attempt was successful.
// CompareExchange attempts to put 1 into syncPoint, but
// only if the current value of syncPoint is zero
// (specified by the third parameter). If another thread
// has set syncPoint to 1, or if the control thread has
// set syncPoint to -1, the current event is skipped.
// (Normally it would not be necessary to use a local
// variable for the return value. A local variable is
// used here to determine the reason the event was
// skipped.)
//
int sync = Interlocked.CompareExchange(ref syncPoint, 1, 0);
if (sync == 0)
{
// No other event was executing.
// The event handler simulates an amount of work
// lasting between 50 and 200 milliseconds, so that
// some events will overlap.
int delay = timerIntervalBase
- timerIntervalDelta / 2 + rand.Next(timerIntervalDelta);
Thread.Sleep(delay);
numExecuted += 1;
// Release control of syncPoint.
syncPoint = 0;
}
else
{
if (sync == 1) { numSkipped += 1; } else { numLate += 1; }
}
}
}
/* On a dual-processor computer, this code example produces
results similar to the following:
Test 100/100 100 test runs completed.
436 events were raised.
352 events executed.
84 events were skipped for concurrency.
0 events were skipped because they were late.
Control thread waited 77 times for an event to complete.
*/
I have a .net based windows service with the following pseudo code. It just goes in loop and based on a condition it either does DoTask() instantly or after 60 seconds. It is done this way to prevent overlapping timer calls when DoTask() is already running.
My question is - if done this way, the code/objects that have already run in DoTask() will ever be garbage collected? Or, since the timer is started from within the DoTask() which is called by timer, the memory stack will just keep increasing?
//called once when the service starts
function_startup
{
mainTimer = new System.Timers.Timer();
mainTimer.Interval = 10;
mainTimer.Elapsed += OnTimedEvent;
mainTimer.AutoReset = false; // makes it fire only once
mainTimer.Start();
}
private void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
//some business logic goes here
DoTask();
}
private void DoTask()
{
//some business logic goes here
//will the code that is here be garbage collected eventually
//or will always stay in memory stack increasing the memory that the service takes while running?
//if condition a, run DoTask immediately again.
if (condition_a)
{
mainTimer.Interval = 10;
mainTimer.Start();
}
//else if condition b, sleep for a minute and then DoTask
else (condition_b)
{
mainTimer.Interval = 60000; //run after 60 seconds
mainTimer.Start();
}
}
There is no memory leak in your code, and also nothing more gets collected or created (from what you have shown).
With the code shown, the timer itself will never be collected or recreated.
If you instantiate classes or structs in the scope of DoTask(), they will fall out of scope when it finishes then will be collected eventually.
Lets say I have a button that gets clicked and it does this:
public void ButtonClick(object sender, EventArgs e)
{
System.Timers.Timer NewTimer = new System.Timers.Timer();
NewTimer.AutoReset = false;
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
}
If this button gets clicked 100 times what happens to those instances that have been created? Will garbage collection kick in or does the System.Timers.Timer.Close method need calling and if it does where do you call it from?
No this will not cause a memory leak. In fact the way your code is written it's not guaranteed to execute properly. Timers.Timer is really just a wrapper over Threading.Timer and it's explicitly listed as being collectable even if it's currently running.
http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
Here you keep no reference to it and hence the very next GC could collect it while your form is still running and before the event ever fires
EDIT
The documentation for Timers.Timer appears to be incorrect. The Timer instance will not be collected if it's unreferenced. It will indeed live on
var timer = new System.Timers.Timer
{
Interval = 400,
AutoReset = true
};
timer.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer.Enabled = true;
WeakReference weakTimer = new WeakReference(timer);
timer = null;
for (int i = 0; i < 100; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine("Weak Reference: {0}", weakTimer.Target);
Console.ReadKey();
They will be collected once method is left. TimerElapsed will be either called or not depending on when Timer gets finalized. Most likely it will be dead long before 1 second passed.
When you call Timer.Close() you thus call Timer.Dispose() that de-registers timer from timer queue and in that case TimerElapsed won't be called (of course if it was not called before).
If you leave timer not closed, GC will eventaully call Finalize() that in turn will call Dispose(). But there is not exact knowledge when it will happen :)
See below example, Console.Out.WriteLine("called!!!") will never execute:
using (System.Timers.Timer NewTimer = new System.Timers.Timer())
{
NewTimer.AutoReset = false;
ElapsedEventHandler TimerElapsed = (sender, args) => { Console.Out.WriteLine("called!!!"); };
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
Thread.Sleep(3000);
After answers by the_joric and JaredPar and running profiler tests which showed timers sticking around after garbage collection kicked in the reason they stuck around was because there is a reference to the event handler sticking around. For a more detailed explanation see this answer.
The real answer is that it is a memory leak unless the timer is closed in the elapsed event handler.
Just goes to show that although I trust the answers on SO (maybe too much) from the great contributors they may be slightly off.
I wanted a timer with the following properties:
No matter how many times start is called, only one call back thread is ever running
The time spent in the call back function was ignored with regards to the interval. E.g if the interval is 100ms and the call back takes 4000ms to execute, the callback is called at 100ms, 4100ms etc.
I couldn't see anything available so wrote the following code. Is there a better way to do this?
/**
* Will ensure that only one thread is ever in the callback
*/
public class SingleThreadedTimer : Timer
{
protected static readonly object InstanceLock = new object();
//used to check whether timer has been disposed while in call back
protected bool running = false;
virtual new public void Start()
{
lock (InstanceLock)
{
this.AutoReset = false;
this.Elapsed -= new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.Elapsed += new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.running = true;
base.Start();
}
}
virtual public void SingleThreadedTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (InstanceLock)
{
DoSomethingCool();
//check if stopped while we were waiting for the lock,
//we don't want to restart if this is the case..
if (running)
{
this.Start();
}
}
}
virtual new public void Stop()
{
lock (InstanceLock)
{
running = false;
base.Stop();
}
}
}
Here's a quick example I just knocked up;
using System.Threading;
//...
public class TimerExample
{
private System.Threading.Timer m_objTimer;
private bool m_blnStarted;
private readonly int m_intTickMs = 1000;
private object m_objLockObject = new object();
public TimerExample()
{
//Create your timer object, but don't start anything yet
m_objTimer = new System.Threading.Timer(callback, m_objTimer, Timeout.Infinite, Timeout.Infinite);
}
public void Start()
{
if (!m_blnStarted)
{
lock (m_objLockObject)
{
if (!m_blnStarted) //double check after lock to be thread safe
{
m_blnStarted = true;
//Make it start in 'm_intTickMs' milliseconds,
//but don't auto callback when it's done (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
}
}
public void Stop()
{
lock (m_objLockObject)
{
m_blnStarted = false;
}
}
private void callback(object state)
{
System.Diagnostics.Debug.WriteLine("callback invoked");
//TODO: your code here
Thread.Sleep(4000);
//When your code has finished running, wait 'm_intTickMs' milliseconds
//and call the callback method again,
//but don't auto callback (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
The .NET Framework provides four timers. Two of these are general-purpose multithreaded
timers:
System.Threading.Timer
System.Timers.Timer
The other two are special-purpose single-threaded timers:
System.Windows.Forms.Timer (Windows Forms timer)
System.Windows.Threading.DispatcherTimer (WPF timer)
The last 2 are designed to eliminate thread-safety issues for WPF and Windows Forms applications.
For example, using WebBrowser inside a timer to capture screenshots from webpage needs to be single-threaded and gives an error at runtime if it is on another thread.
The single-thread timers have the following benefits
You can forget about thread safety.
A fresh Tick will never fire until the previous Tick has finished
processing.
You can update user interface elements and controls directly from
Tick event handling code, without calling Control.BeginInvoke or
Dispatcher.BeginIn voke.
and main disadvantage to note
One thread serves all timers—as well as the processing UI events.
Which means that the Tick event handler must execute quickly,
otherwise the user interface becomes unresponsive.
source: most are scraps from C# in a Nutshell book -> Chapter 22 -> Advanced threading -> Timers -> Single-Threaded Timers
For anyone who needs a single thread timer and wants the timer start to tick after task done.
System.Timers.Timer could do the trick without locking or [ThreadStatic]
System.Timers.Timer tmr;
void InitTimer(){
tmr = new System.Timers.Timer();
tmr.Interval = 300;
tmr.AutoReset = false;
tmr.Elapsed += OnElapsed;
}
void OnElapsed( object sender, System.Timers.ElapsedEventArgs e )
{
backgroundWorking();
// let timer start ticking
tmr.Enabled = true;
}
Credit to Alan N
source https://www.codeproject.com/Answers/405715/System-Timers-Timer-single-threaded-usage#answer2
Edit: spacing
Look at the [ThreadStatic] attribute and the .Net 4.0 ThreadLocal generic type. This will probably quickly give you a way to code this without messing with thread locking etc.
You could have a stack inside your time class, and you could implement a Monitor() method that returns a IDisposable, so you can use the timer like so:
using (_threadTimer.Monitor())
{
// do stuff
}
Have the timer-monitor pop the the interval timestamp off the stack during Dispose().
Manually coding all the locking and thread recognition is an option as has been mentioned. However, locking will influence the time used, most likely more than having to initialize an instance per thread using ThreadLocal
If you're interested, I might knock up an example later
Here is a simple PeriodicNonOverlappingTimer class, that provides just the requested features, and nothing more than that. This timer cannot be started and stopped on demand, and neither can have its interval changed. It just invokes the specified action periodically in a non overlapping manner, until the timer is disposed.
/// <summary>
/// Invokes an action on the ThreadPool at specified intervals, ensuring
/// that the invocations will not overlap, until the timer is disposed.
/// </summary>
public class PeriodicNonOverlappingTimer : IDisposable, IAsyncDisposable
{
private readonly System.Threading.Timer _timer;
public PeriodicNonOverlappingTimer(Action periodicAction,
TimeSpan dueTime, TimeSpan period)
{
// Arguments validation omitted
_timer = new(_ =>
{
var stopwatch = Stopwatch.StartNew();
periodicAction();
var nextDueTime = period - stopwatch.Elapsed;
if (nextDueTime < TimeSpan.Zero) nextDueTime = TimeSpan.Zero;
try { _timer.Change(nextDueTime, Timeout.InfiniteTimeSpan); }
catch (ObjectDisposedException) { } // Ignore this exception
});
_timer.Change(dueTime, Timeout.InfiniteTimeSpan);
}
public void Dispose() => _timer.DisposeAsync().AsTask().Wait();
public ValueTask DisposeAsync() => _timer.DisposeAsync();
}
Usage example. Shows how to create a non-overlapping timer that starts immediately, with a period of 10 seconds.
var timer = new PeriodicNonOverlappingTimer(() =>
{
DoSomethingCool();
}, TimeSpan.Zero, TimeSpan.FromSeconds(10));
//...
timer.Dispose(); // Stop the timer once and for all
In case the DoSomethingCool fails, the exception will be thrown on the ThreadPool, causing the process to crash. So you may want to add a try/catch block, and handle all the exceptions that may occur.
The Dispose is a potentially blocking method. If the periodicAction is currently running, the Dispose will block until the last invocation is completed.
If you don't want to wait for this to happen, you can do this instead:
_ = timer.DisposeAsync(); // Stop the timer without waiting it to finish
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I need to create some windows service which will execute every N period of time.
The question is:
Which timer control should I use: System.Timers.Timer or System.Threading.Timer one? Does it influence on something?
I am asking because I heard many evidences to non correct work of System.Timers.Timer in windows services.
Thank you.
Both System.Timers.Timer and System.Threading.Timer will work for services.
The timers you want to avoid are System.Web.UI.Timer and System.Windows.Forms.Timer, which are respectively for ASP applications and WinForms. Using those will cause the service to load an additional assembly which is not really needed for the type of application you are building.
Use System.Timers.Timer like the following example (also, make sure that you use a class level variable to prevent garbage collection, as stated in Tim Robinson's answer):
using System;
using System.Timers;
public class Timer1
{
private static System.Timers.Timer aTimer;
public static void Main()
{
// Normally, the timer is declared at the class level,
// so that it stays in scope as long as it is needed.
// If the timer is declared in a long-running method,
// KeepAlive must be used to prevent the JIT compiler
// from allowing aggressive garbage collection to occur
// before the method ends. (See end of method.)
//System.Timers.Timer aTimer;
// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
/* This code example produces output similar to the following:
Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
*/
If you choose System.Threading.Timer, you can use as follows:
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();
}
}
}
Both examples comes from the MSDN pages.
Don't use a service for this. Create a normal application and create a scheduled task to run it.
This is the commonly held best practice. Jon Galloway agrees with me. Or maybe its the other way around. Either way, the fact is that it is not best practices to create a windows service to perform an intermittent task run off a timer.
"If you're writing a Windows Service that runs a timer, you should re-evaluate your solution."
–Jon Galloway, ASP.NET MVC community program manager, author, part time superhero
Either one should work OK. In fact, System.Threading.Timer uses System.Timers.Timer internally.
Having said that, it's easy to misuse System.Timers.Timer. If you don't store the Timer object in a variable somewhere, then it is liable to be garbage collected. If that happens, your timer will no longer fire. Call the Dispose method to stop the timer, or use the System.Threading.Timer class, which is a slightly nicer wrapper.
What problems have you seen so far?
I agree with previous comment that might be best to consider a different approach. My suggest would be write a console application and use the windows scheduler:
This will:
Reduce plumbing code that replicates scheduler behaviour
Provide greater flexibility in terms
of scheduling behaviour (e.g. only
run on weekends) with all scheduling logic abstracted from application code
Utilise the command line arguments
for parameters without having to
setup configuration values in config
files etc
Far easier to debug/test during development
Allow a support user to execute by invoking
the console application directly
(e.g. useful during support
situations)
As already stated both System.Threading.Timer and System.Timers.Timer will work. The big difference between the two is that System.Threading.Timer is a wrapper arround the other one.
System.Threading.Timer will have more exception handling while
System.Timers.Timer will swallow all the exceptions.
This gave me big problems in the past so I would always use 'System.Threading.Timer' and still handle your exceptions very well.
I know this thread is a little old but it came in handy for a specific scenario I had and I thought it worth while to note that there is another reason why System.Threading.Timer might be a good approach.
When you have to periodically execute a Job that might take a long time and you want to ensure that the entire waiting period is used between jobs or if you don't want the job to run again before the previous job has finished in the case where the job takes longer than the timer period.
You could use the following:
using System;
using System.ServiceProcess;
using System.Threading;
public partial class TimerExampleService : ServiceBase
{
private AutoResetEvent AutoEventInstance { get; set; }
private StatusChecker StatusCheckerInstance { get; set; }
private Timer StateTimer { get; set; }
public int TimerInterval { get; set; }
public CaseIndexingService()
{
InitializeComponent();
TimerInterval = 300000;
}
protected override void OnStart(string[] args)
{
AutoEventInstance = new AutoResetEvent(false);
StatusCheckerInstance = new StatusChecker();
// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate =
new TimerCallback(StatusCheckerInstance.CheckStatus);
// Create a timer that signals the delegate to invoke
// 1.CheckStatus immediately,
// 2.Wait until the job is finished,
// 3.then wait 5 minutes before executing again.
// 4.Repeat from point 2.
Console.WriteLine("{0} Creating timer.\n",
DateTime.Now.ToString("h:mm:ss.fff"));
//Start Immediately but don't run again.
StateTimer = new Timer(timerDelegate, AutoEventInstance, 0, Timeout.Infinite);
while (StateTimer != null)
{
//Wait until the job is done
AutoEventInstance.WaitOne();
//Wait for 5 minutes before starting the job again.
StateTimer.Change(TimerInterval, Timeout.Infinite);
}
//If the Job somehow takes longer than 5 minutes to complete then it wont matter because we will always wait another 5 minutes before running again.
}
protected override void OnStop()
{
StateTimer.Dispose();
}
}
class StatusChecker
{
public StatusChecker()
{
}
// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} Start Checking status.",
DateTime.Now.ToString("h:mm:ss.fff"));
//This job takes time to run. For example purposes, I put a delay in here.
int milliseconds = 5000;
Thread.Sleep(milliseconds);
//Job is now done running and the timer can now be reset to wait for the next interval
Console.WriteLine("{0} Done Checking status.",
DateTime.Now.ToString("h:mm:ss.fff"));
autoEvent.Set();
}
}