2014-12-27 31 views
3

我想使用System.Threading.Timer执行一次。该计时器应该在不再需要时立即致电Dispose进行确定性清理(这是回调触发时)。一次性System.Threading.Timer如何处理自己?

问题是回调不能可靠地获得Timer的引用!

System.Threading.Timer timer = null; 
timer = new System.Threading.Timer(_ => 
{ 
    Console.WriteLine("Elapsed."); 

    //Dispose the timer here, but timer might be null! 
    timer.Dispose(); //BUG 
}, null, TimeSpan.FromSeconds(1), TimeSpan.Zero); 

变量timer在回调触发时可能不会被初始化。此代码在所有情况下都不起作用,因为它包含竞争条件。

我们如何使用System.Threading.Timer创建具有确定性清理的一次性定时器?

(更好的方法来创建一个单次计时器/延迟超出范围的这个问题。我有意以特定的方式问这个。)

回答

5

更改为只接收回调,因此constructor of Timer它会在的状态参数中传递自己。使用Change()设置它随即:

 System.Threading.Timer timer = null; 
     timer = new System.Threading.Timer((state) => 
     { 
      Console.WriteLine("Elapsed."); 

      // Dispose of the timer here: 
      ((System.Threading.Timer)state).Dispose(); 
     }); 
     timer.Change(TimeSpan.FromSeconds(1), TimeSpan.Zero); 

如果你不喜欢用state参数也可以使用闭包变量如你问题确实它的代码。关键不是用构造函数启动计时器。只有在存储了对定时器的引用后才能启动它。

+0

这应该做的工作。 Task.Delay方法具有与我讨论的相同的竞争条件。另外,他们在DelayPromise.Timer字段上有数据竞争。 – usr 2014-12-27 18:36:35