Reputation: 21999
I want something very simple
// increment counter
Interlocked.Increment(ref _counter);
// automatically decrement counter after 1 sec
Timer timer = new Timer((o) => {
Interlocked.Decrement(ref _counter);
(o as Timer).Dispose();
}, timer, 1000, Timeout.Infinite);
this code, however, is not compile-able
Use of unassigned local variable 'timer'
Any easy way to fix that? It must be Threading.Timer
.
P.S.: I am not sure if I must call Dispose
, it's obviously un-managed resource and it's IDisposable
, still on msdn they warn
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.
And I actually want it to be be collected (auto-disposed?). So, to dispose or to not dispose?
Upvotes: 6
Views: 2080
Reputation: 11
If it's important that you dispose, you should try this:
class Foo {
private Timer _timer;
...
public void IncrementForASecond()
{
Interlocked.Increment(ref _counter);
if(_timer != null)
_timer.Dispose();
_timer = new Timer((o) => {
Interlocked.Decrement(ref _counter);
}, null, 1000, Timeout.Infinite);
}
This way, you are making sure that you always have a reference to the timer and that you are disposing of the previous timer before creating a new one.
Upvotes: 0
Reputation: 171178
There's a pattern for that:
Timer timer = null;
timer = new Timer...
Now you can use timer
in the lambda body. This is basically a way to make the compiler happy while doing the same thing.
Be sure to dispose of that timer. Timers might be backed up by an OS handle resource (the CLR implementation changed a few times I believe). A timer also contains a GC handle I believe. This is harmless not to dispose of most of the time. But who knows what rare resource exhaustion you can provoke with a high volume of undisposed timers.
Doing a little code review: If you expect a cast to always work, do not use as
because as
documents that failure is an expected case. Not: (o as Timer)
. Instead: ((Timer)o)
.
Upvotes: 6
Reputation: 13976
Self disposing won't work if you don't keep a reference to it. You risk having it garbage collected, even if it's not periodical. So, it may be garbage collected before even it ticks the first time.
From the System.Threading.Timer documentation:
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.
On the other hand, it will be released via it's finalizer even if you don't dispose it (although not a good practice to rely on this). This can be seen in the Timer's source, on ReferenceSource.
Upvotes: 3