Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Auto-dispose Threading.Timer

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?

like image 507
Sinatr Avatar asked Aug 11 '14 10:08

Sinatr


People also ask

How do you dispose of a timer?

Best practices when working in C# say that you should clean up your resources if the class implements IDisposable interface. There are two ways to dispose the Timer: Dispose the timer by calling the Dispose() method inside a try/catch block to avoid exception.

Is system threading timer thread safe?

Timer is not thread-safe.

How do you stop a timer thread?

To end or quit the timer, one must use a cancel() function. Importing the threading class is necessary for one to use the threading class. The calling thread can be suspended for seconds using the function time. sleep(secs).

How does system threading timer work?

The application thread creates the timer, which waits one second and then executes the CheckStatus callback method every 250 milliseconds. The application thread then blocks until the AutoResetEvent object is signaled. When the CheckStatus callback method executes maxCount times, it calls the AutoResetEvent.


2 Answers

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).

like image 149
usr Avatar answered Oct 23 '22 13:10

usr


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.

like image 3
Marcel N. Avatar answered Oct 23 '22 12:10

Marcel N.