自动处理Threading.Timer

时间:2014-08-11 10:26:29

标签: c# timer lambda dispose

我想要一些非常简单的东西

// 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);
然而,

此代码不可编译

  

使用未分配的本地变量'计时器'

任何简单的方法来解决这个问题?它必须是Threading.Timer

PS:我不确定我必须致电Dispose,它显然是未经管理的资源,它是IDisposable,仍在msdn他们发出警告

  

只要您使用Timer,就必须保留对它的引用。与任何托管对象一样,当没有对它的引用时,Timer会进行垃圾回收。定时器仍处于活动状态这一事实并不能阻止它被收集。

我真的希望它被收集(自动处理?)。那么,处置还是不处置?

3 个答案:

答案 0 :(得分:6)

有一种模式:

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

现在你可以在lambda体中使用timer。这基本上是一种让编译器在做同样事情时感到高兴的方法。

请务必丢弃该计时器。定时器可能由OS句柄资源备份(我认为CLR实现改变了几次)。我相信计时器还包含GC手柄。没有处理的大部分时间是无害的。但是谁知道你可以用大量不受控制的计时器引发的稀有资源耗尽。

进行一些代码审查:如果您希望演员表始终有效,请不要使用as,因为as表示失败是预期的情况。不是:(o as Timer)。相反:((Timer)o)

答案 1 :(得分:3)

如果您不保留对它的引用,则自行处理将不起作用。即使它不是周期性的,你也有可能收集垃圾。因此,它可能是垃圾收集,甚至在它第一次滴答之前。

来自System.Threading.Timer文档:

  

只要您使用Timer,就必须保留对它的引用。如   使用任何托管对象时,Timer都会进行垃圾回收   没有提及它。 Timer仍然有效的事实   不会阻止它被收集。

另一方面,它会通过它的终结器释放,即使你不处理它(虽然不是一个好的做法,依靠这个)。这可以在Timer的源代码on ReferenceSource中看到。

答案 2 :(得分:0)

如果你处理它很重要,你应该试试这个:

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);
  }

通过这种方式,您可以确保始终拥有对计时器的引用,并确保在创建新计时器之前处理之前的计时器。