2014-12-27 30 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