Reputation: 35982
Given the following code, the timer will trigger the PrintTimer function every one second until the user presses a key.
Question 1> When the Timer will be stopped? Is the Timer by default a Background thread so it will be killed after the foreground thread is terminated.
Question 2> How to programmatically stop the timer in the calling thread?
class Program
{
// continue to call this function until the user presses a
// key to terminate the application
static void PrintTime(object state)
{
Console.WriteLine("Time is: {0}",
DateTime.Now.ToLongTimeString());
}
static void Main(string[] args)
{
TimerCallback timeCB = new TimerCallback(PrintTime);
System.Threading.Timer t = new Timer(
timeCB,
null,
0,
1000);
Console.WriteLine("Hit key to terminate...");
Console.ReadLine();
}
}
Upvotes: 0
Views: 2709
Reputation: 4570
For Question 2 see the Timer.Enabled property and the Timer.Close() method
Update: I suppose for completeness I should also have mentioned the Timer.Stop() method (which sets Enabled to false)
Update: When should each option be used?
Broadly speaking there are two situations: either you are getting rid of the timer and never plan to use it again or else you are pausing the timer but plan to revive it at some point (or at least want the option to be able to revive it).
If you are getting rid of the timer then Dispose/Close is the route to take. At minimum you should call Dispose because that's what a well behaved program is expected to do when it is finished with an object that implements IDisposable.
That said, when an object implements both IDisposable and a Close method I believe the better approach is to call Close because Close may do more than just free resources. For example it might flush buffers or do some other object specific thing. One would expect a Close method to call Dispose. Ideally the documentation for Close would explicitly state that it calls Dispose (but the documentation for Timer::Close does not say that it does).
To temporarily pause and revive a timer you can set the Enabled property to false and then set it to true again. Alternatively you can call Stop() and then call Start() to revive it. Off hand I don't have a preference for one technique over the other.
I suppose one might argue that Stop and Start are slightly more readable and perhaps slightly less efficient (since they in turn set Enabled).
Upvotes: 1
Reputation: 7348
In your application it will never stop until you exit your application.
To stop it programatically, it depends on which timer are you using.
System.Timers.Timer
System.Threading.Timer
If the first one, you can call the Stop method. If the second one, you have to Dispose() it.
Please note that if you start the timer in a method and don't keep a reference to it, it will be stopped when it gets garbage collected.
Upvotes: 1
Reputation: 33379
Answer 1
Right now the timer will be stopped only when the Program exits. It's not really sitting there using a background thread, but when the timer event occurs the callback will be invoked via a ThreadPool thread which is a background thread.
Answer 2
Stopping the timer is as simple as either:
t.Change(Timeout.Infinite, Timeout.Infinite);
-- or --
t.Dispose();
The former allows you to restart the Timer
with another call to Change
where as the latter will clean up the Timer
entirely.
For more detailed information on its behavior, I suggest reading the Remarks section of the Timer
class in its MSDN documentation. For instance, there's some tricky timing with Dispose
because the Timer
may have already queued up a notification callback to the thread pool which you could technically receive even after calling Dispose
.
Upvotes: 4
Reputation: 3380
The timer will be cleaned up with its finzalizer runs. That's when it becomes garabage, which actually varies from release to debug mode.
Here's a test we can run using WeakReference:
internal class Program
{
// continue to call this function until the user presses a
// key to terminate the application
private static void PrintTime(object state)
{
Console.WriteLine("Time is: {0}",
DateTime.Now.ToLongTimeString());
}
private static void Main(string[] args)
{
TimerCallback timeCB = new TimerCallback(PrintTime);
Timer t = new Timer(
timeCB,
null,
0,
1000);
WeakReference wk = new WeakReference(t);
PrintStatus(wk);
Console.WriteLine("Hit key to terminate...");
Console.ReadLine();
t = null;
PrintStatus(wk);
}
private static void PrintStatus(WeakReference wk)
{
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("Is timer alive? " + wk.IsAlive);
}
}
Upvotes: 2
Reputation: 7452
Timer
is disposable so you should/must call Dispose
on it. You can also call Stop
if you want to reuse it but there is a bug in the Timer class with a periodic callback that makes it advisable to just Dispose it and start with a new timer.
What will happen in the code that you have posted is that the Timer's finalizer will (technically may) be called which will kill it.
Upvotes: 1