Question 1:
Hi, I would like to know is there a way by which I can dispose or kill the object of DispatcherTimer and create a new object of same name?
Question 2:
Can I access the DispatcherTimer object in some other class if it is set to Public?
You cannot dispose DispatcherTimer object. It doesn't implement IDisposable interface. You cannot explicit kill (free, destroy) objects in managed world.
If you don't need the timer object any more, disable it and set reference to it to null. It will be collected later by GC.
You can disable or stop the timer by setting IsEnabled = false or call timer.Stop(). The effect is the same.
Yes. I suppose you have public property like this:
public DispatcherTimer MyTimer { get; private set; }
Adding to a correct answer from Lubo (and bringing up this topic from comments under it): even though you cannot dispose DispatcherTimer (most probably, because it's wired up to unmanaged part of the WPF / UWP Dispatcher itself which lives as long as the app itself), you still should unsubscribe from its events.
Say, if you had some method (StartRefreshTimer) where you initialized your DispatcherTimer and started listening to its Tick event:
private DispatcherTimer _refreshTimer = new DispatcherTimer() { Interval = TimeSpan.FromMinutes(1) };
private void StartRefreshTimer()
{
if (_refreshTimer != null)
{
_refreshTimer.Tick += OnTick; // subscribe to timer's ticks
_refreshTimer.Start(); // start timer
}
}
private void OnTick(object sender, object args)
{
// your custom OnTick logic
}
Then you should have a method which stops the timer and unsubscribes from its events:
private void StopRefreshTimer()
{
if (_refreshTimer != null)
{
_refreshTimer.Stop(); // stop timer
_refreshTimer.Tick -= OnTick; // unsubscribe from timer's ticks
}
}
You should make sure you call this "tear down" method when your class goes out of scope (for example, when your WPF / UWP control or ViewModel is unloaded). If you don't unsubscribe from timer events you could end up with memory leaks caused by references from outer scope to your timer hosting class.
Related
Preface: I know how to solve the problem. I want to know why it arises. Please read the question from top to bottom.
As we all (should) know, adding event handlers can cause memory leaks in C#. See Why and How to avoid Event Handler memory leaks?
On the other hand, objects often have similar or connected life cycles and deregistering event handlers is not necessary. Consider this example:
using System;
public class A
{
private readonly B b;
public A(B b)
{
this.b = b;
b.BEvent += b_BEvent;
}
private void b_BEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler AEvent;
}
public class B
{
private readonly A a;
public B()
{
a = new A(this);
a.AEvent += a_AEvent;
}
private void a_AEvent(object sender, EventArgs e)
{
// NoOp
}
public event EventHandler BEvent;
}
internal class Program
{
private static void Main(string[] args)
{
B b = new B();
WeakReference weakReference = new WeakReference(b);
b = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool stillAlive = weakReference.IsAlive; // == false
}
}
A and B reference each other implicitly via events, yet the GC can delete them (because it's not using reference counting, but mark-and-sweep).
But now consider this similar example:
using System;
using System.Timers;
public class C
{
private readonly Timer timer;
public C()
{
timer = new Timer(1000);
timer.Elapsed += timer_Elapsed;
timer.Start(); // (*)
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// NoOp
}
}
internal class Program
{
private static void Main(string[] args)
{
C c = new C();
WeakReference weakReference = new WeakReference(c);
c = null;
GC.Collect();
GC.WaitForPendingFinalizers();
bool stillAlive = weakReference.IsAlive; // == true !
}
}
Why can the GC not delete the C object? Why does the Timer keep the object alive? Is the timer kept alive by some "hidden" reference of the timer mechanics (e.g. a static reference)?
(*) NB: If the timer is only created, not started, the issue does not occur. If it's started and later stopped, but the event handler is not deregistered, the issue persists.
The timer logic relies on an OS functionality. It is actually the OS that fires the event. OS in turn uses CPU interrupts to implement that.
The OS API, aka Win32, does not hold references to any objects of any kind. It holds memory addresses of functions which it has to call when a timer event happens. .NET GC has no way to track such "references". As a result a timer object could be collected without unsubscribing from the low-level event. It is a problem because OS would try to call it anyway and would crash with some weird memory access exception. That's why .NET Framework holds all such timer objects in the statically referenced object and removes them from that collection only when you unsubscribe.
If you look at the root of your object using SOS.dll you will get the next picture:
!GCRoot 022d23fc
HandleTable:
001813fc (pinned handle)
-> 032d1010 System.Object[]
-> 022d2528 System.Threading.TimerQueue
-> 022d249c System.Threading.TimerQueueTimer
-> 022d2440 System.Threading.TimerCallback
-> 022d2408 System.Timers.Timer
-> 022d2460 System.Timers.ElapsedEventHandler
-> 022d23fc TimerTest.C
Then if you look at the System.Threading.TimerQueue class in something like dotPeek, you will see that it is implemented as a singleton and it holds a collection of timers.
That's how it works. Unfortunately the MSDN documentation is not crystal clear about it. They just assumed that if it implements IDisposable then you should dispose it no question asked.
Is the timer kept alive by some "hidden" reference of the timer mechanics (e.g. a static reference)?
Yes. It is built in the CLR, you can see a trace of it when you use the Reference Source or a decompiler, the private "cookie" field in the Timer class. It is passed as the second argument to the System.Threading.Timer constructor that actually implements the timer, the "state" object.
The CLR keeps a list of enabled system timers and adds a reference to the state object to ensure it doesn't get garbage collected. Which in turn ensures that the Timer object doesn't get garbage collected as long as it is in the list.
So getting a System.Timers.Timer garbage collected requires that you call its Stop() method or set its Enabled property to false, same thing. Which cause the CLR to remove the system timer from the list of active timers. Which also removes the reference to the state object. Which then makes the timer object eligible for collection.
Clearly this is desirable behavior, you do not typically want to have a timer just disappear and stop ticking while it is active. Which will happen when you use a System.Threading.Timer, it stops calling its callback if you don't keep a reference to it, either explicitly or by using the state object.
I think this is related to the way that the Timer is implemented. When you call Timer.Start(), it sets Timer.Enabled = true. Look at the implementation of Timer.Enabled:
public bool Enabled
{
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
get
{
return this.enabled;
}
set
{
if (base.DesignMode)
{
this.delayedEnable = value;
this.enabled = value;
}
else if (this.initializing)
{
this.delayedEnable = value;
}
else if (this.enabled != value)
{
if (!value)
{
if (this.timer != null)
{
this.cookie = null;
this.timer.Dispose();
this.timer = null;
}
this.enabled = value;
}
else
{
this.enabled = value;
if (this.timer == null)
{
if (this.disposed)
{
throw new ObjectDisposedException(base.GetType().Name);
}
int dueTime = (int) Math.Ceiling(this.interval);
this.cookie = new object();
this.timer = new Timer(this.callback, this.cookie, dueTime, this.autoReset ? dueTime : 0xffffffff);
}
else
{
this.UpdateTimer();
}
}
}
}
}
It looks like a new timer is created, with a cookie object passed to it (very odd!). Following that call path leads to some other complex code involving creating a TimerHolder and a TimerQueueTimer. I expect at some point a reference held outside the Timer itself is created, until such time as you call Timer.Stop() or Timer.Enabled = false.
This isn't a definitive answer, since none of the code I posted creates such a reference; but it's complicated enough down in the guts to lead me to suspect that something like that is happening.
If you have Reflector (or similar) have a look and you'll see what I mean. :)
Because Timer is still active. (Event handler is not removed for Timer.Elapsed).
If you want to properly dispose, Implement IDisposable interface, remove the event handler in the Dispose method, and use the using block or call the Dispose manually. The issue will not occur.
Example
public class C : IDisposable
{
...
void Dispose()
{
timer.Elapsed -= timer_elapsed;
}
}
And then
C c = new C();
WeakReference weakReference = new WeakReference(c);
c.Dispose();
c = null;
I think the problem arises from this line;
c = null;
In general, most developers think that making an object equal to null results in object to be deleted by garbage collector. But this is not the case; in fact only a reference to a memory location (where c object is created) is deleted; if there are any other references to the related memory location, object will not be marked for deletion. In this case, since Timer is referencing the related memory location, object will not be deleted by garbage collector.
Let's first talk about Threading.Timer. Internally, the timer will construct a TimerQueueTimer object using callback and state passed to Timer ctor (say new Threading.Timer(callback, state, xxx, xxx). The TimerQueueTimer will be added to a static list.
If callback method and state have no "this" info (say using static method for callback and null for state), then the Timer object can be GCed when no reference.
On the other hand, if a member method is used for callback, the delegate containing "this" will be stored in the static list mentioned above. So Timer object cannot be GCed since the "C" (in your example) object is still referenced.
Now let's back to System.Timers.Timer which internally wraps Threading.Timer. Note that when the former constructs the latter, a System.Timers.Timer member method is used, so System.Timers.Timer object cannot be GCed.
I am in C# .NET 3.5
What happens when timer elapses and event handler is performed ?
Does the timer cease to exist ?
Can I register several events in different time on one timer, expecting them all to fire one after another ?
You can set a timer to fire off the event only once or continue to do it (Timer.AutoReset property). Yes, you can register several different event handlers on a single timer, but I don't know that there is any way of knowing what order they will fire. If that matters to you, set a single handler, and have that handler call the others. If what you are trying to do is to call a different handler, each time the timer goes off, I would suggest setting a single handler that keeps an enum indicating which function to call and incrementing it each time it gets called by the timer.
To call the same handler to "iterate" through a list of parameters, once on each interval elapsed, I would have an array or list of the parameters and the handler would just increase a counter or consume the list.
using System.Timers;
public class MyTimedDelete {
private static List<int> ListOfIds=null;
private static System.Timers.Timer myTimer=null;
public static void AddIdToQueue(int id)
{
if (ListOfIds == null)
{
ListOfIds = new List<int>();
myTimer = new System.Timers.Timer(2000);
myTimer.Elapsed += OnTimedEvent;
}
ListOfIds.Add(id);
if (ListOfIds.Count==1)
{
myTimer.Start();
}
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
deleteItem(ListOfIds[0]);
ListOfIds.RemoveAt(0);
if (ListOfIds.Count == 0) {
myTimer.Stop();
}
}
}
I have a project here and it has set by default that the actions occur by MouseEnter event. I mean, opening a Window, closing, returning, whatever, happens only by the MouseEnter event.
I was requested to make the event fire only after 3 seconds. That means that the user will place the mouse on the control and only after 3 seconds the event must happen for all the controls in the window.
So, I thought about a global timer or something alike, that will return false untill the timer reaches 3... I think that's the way...
Geez, does anybody knows how can I make such thing?
Thanks!!
You can define a class that will expose a DelayedExecute method that receives an action to execute and creates timers as needed for the delayed execution. It would look something like this:
public static class DelayedExecutionService
{
// We keep a static list of timers because if we only declare the timers
// in the scope of the method, they might be garbage collected prematurely.
private static IList<DispatcherTimer> timers = new List<DispatcherTimer>();
public static void DelayedExecute(Action action, int delay = 3)
{
var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
// Add the timer to the list to avoid it being garbage collected
// after we exit the scope of the method.
timers.Add(dispatcherTimer);
EventHandler handler = null;
handler = (sender, e) =>
{
// Stop the timer so it won't keep executing every X seconds
// and also avoid keeping the handler in memory.
dispatcherTimer.Tick -= handler;
dispatcherTimer.Stop();
// The timer is no longer used and shouldn't be kept in memory.
timers.Remove(dispatcherTimer);
// Perform the action.
action();
};
dispatcherTimer.Tick += handler;
dispatcherTimer.Interval = TimeSpan.FromSeconds(delay);
dispatcherTimer.Start();
}
}
Then you can call it like this:
DelayedExecutionService.DelayedExecute(() => MessageBox.Show("Hello!"));
or
DelayedExecutionService.DelayedExecute(() =>
{
DoSomething();
DoSomethingElse();
});
I just wanted to add a simpler solution:
public static void DelayedExecute(Action action, int delay = 3000)
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(delay);
action();
}
}
Then use it just like in this other answer
I want to build a windows Service, which should execute different methods at different times. Its not about accuracy at all.
Im using a system.timers.timer, and regulate the different methods to be executed within the Eventhandler-method with counters. Thats working allright that far.
All of the methods are accessing a COM-port, making it neccessary to grant acceess-rights to only one method at a time. But since the methods can take some time to finish, the timer might tick again and want to execute another method while the COM-port is still being occupied. In this case, the event can and should just be dismissed.
Simplified down to one method, my elapsedEventHandler-method looks something like the following (try-catch and the different methods excluded here)
Note: While this is running perfectly on my Win7 x64, it struggles on a Win7 x86 machine with pretty much the very same software installed, whenever the method to be executed takes a long time. The timer wont tick any more, no Exception is thrown. Nothing! my question now is: Am I doing the part with access-control and the timer right, so that i can focus on other things? Im just not that familiar with timers and especially threading
private static int m_synchPoint=0;
private System.Timers.Timer timerForData = null;
public MyNewService()
{
timerForData = new System.Timers.Timer();
timerForData.Interval = 3000;
timerForData.Elapsed += new ElapsedEventHandler(Timer_tick);
}
//Initialize all the timers, and start them
protected override void OnStart(string[] args)
{
timerForData.AutoReset = true;
timerForData.Enabled = true;
timerForData.Start();
}
//Event-handled method
private void Timer_tick(object sender, System.Timers.ElapsedEventArgs e)
{
////safe to perform event - no other thread is running the event?
if (System.Threading.Interlocked.CompareExchange(ref m_synchPoint, 1, 0) == 0)
{
//via different else-ifs basically always this is happening here, except switching aMethod,bMethod...
processedevent++;
Thread workerThread = new Thread(aMethod);
workerThread.Start();
workerThread.Join();
m_synchPoint=0;
}
else
{
//Just dismiss the event
skippedevent++;
}
}
Thank you very much in advance!
Any help is greatly appreciated!
I would recommend using System.Threading.Timer for this functionality. You can disable the timer when it executes, process your data, then re-enable the timer.
EDIT:
I think it makes more sense to use System.Threading.Timer because there isn't really a reason you need to drop the timer on a design surface, which is pretty much the only reason to use System.Timers.Timer. I really wish MS would remove it anyways, it's wrapping System.Threading.Timer which isn't all that difficult to use in the first place.
Yes, you do risk a problem with re-entrancy which is why I specified to change the timeout toTimeout.Infinite. You won't have this re-entrancy problem if you construct the timer with Timeout.Infinite.
public class MyClass
{
private System.Threading.Timer _MyTimer;
public MyClass()
{
_MyTimer = new Timer(OnElapsed, null, 0, Timeout.Infinite);
}
public void OnElapsed(object state)
{
_MyTimer.Change(Timeout.Infinite, Timeout.Infinite);
Console.WriteLine("I'm working");
_MyTimer.Change(1000, Timeout.Infinite);
}
}
If you want just skip method invocation while previous method didn't finish just use Monitor.TryEnter(lockObject) before calling your method.
EDIT:
Here's an example -
public class OneCallAtATimeClass
{
private object syncObject;
public TimerExample()
{
syncObject = new object();
}
public void CalledFromTimer()
{
if (Monitor.TryEnter(syncObject);)
{
try
{
InternalImplementation();
}
finally
{
Monitor.Exit(syncObject);
}
}
}
private void InternalImplementation()
{
//Do some logic here
}
}
You can try this:
When the timer fires, disable the timer.
When the task is complete, re-enable the timer...possibly in the Finally clause.
You correctly use CompareExchange to test and set the m_synchPoint field when doing the initial check. You incorrectly use direct assignment to reset the value to 0 at the end of the method. You should use Interlocked.Exchange instead to reset the value to 0. As a side note, you should also change m_synchPoint to an instance field -- it should not be static.
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