Automatic removal of Threading.Timer

I need 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, does not compile

Using the unrecognized local variable 'timer'

Any easy way to fix this? This should be Threading.Timer .

PS: I'm not sure that I should call Dispose , this is clearly not a managed resource, and it is IDisposable , they still warn on msdn

As long as you use the timer, you must keep a link to it. As with any managed object, the timer is subject to garbage collection when there are no references to it. The fact that the timer is still active does not prevent it from gathering.

And I really want to be collected (automatically removed?). So, to dispose or not to dispose?

+6
source share
3 answers

Here is the template for this:

 Timer timer = null; timer = new Timer... 

Now you can use the timer in the lambda body. This is basically a way to make the compiler happy by doing the same.

Be sure to discard this timer. Timers can be backed up by an OS descriptor resource (CLR implementation has changed several times). I believe the timer also contains a GC knob. It is safe not to use most of the time. But who knows what a rare depletion of resources you can provoke with a large amount of undisclosed timers.

Perform a short code review. If you expect the cast to always work, do not use as , because as documents that the failure is expected. Not: (o as Timer) . Instead: ((Timer)o) .

+6
source

Standing alone will not work if you do not refer to it. You run the risk of getting collected garbage, even if it is not periodic. So it could be garbage collection before it starts ticking for the first time.

From the System.Threading.Timer documentation:

As long as you use the timer, you must keep a link to it. In the view with any managed object, the Timer is garbage collected when there are no links to it. The fact that the timer is still active does not prevent it from gathering.

On the other hand, it will be released through the finalizer, even if you do not destroy it (although it is not a good practice to rely on it). This can be seen in the timer source, in the ReferenceSource .

+2
source

If it is important that you dispose, you should try the following:

 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 will ensure that you always have a reference to the timer and that you delete the previous timer before creating a new one.

0
source

Source: https://habr.com/ru/post/973644/


All Articles