Dot-Net

如何安全地處理 System.Timers.Timer?

  • November 26, 2010

當您處理“原始”.net 計時器時,您可以傳入一個等待句柄,以便在 Win32 計時器被銷毀後呼叫,並且您可以假設您的回調不會被呼叫。(並且計時器將被 GC 視為“死”)

如何使用 System.Timers.Timer 執行此操作?

由於 System.Timers.Timer 和 System.Windows.Forms.Timer 都使用 ThreadPool 它沒有作業系統計時器的句柄,因此沒有處理本地計時器資源 - 只是一個完整的執行緒。我不確定您是否可以擷取 ThreadPool 正在回收的執行緒,但我可能錯了。

你也許可以自己動手(我還沒有測試過,在 Dispose 中使用 ManualResetEvent 可能更有用):

void Run()
{
   ManualResetEvent resetEvent = new ManualResetEvent(false);

   System.Threading.Timer timer = new System.Threading.Timer(delegate { Console.WriteLine("Tick"); });
   timer.Dispose(resetEvent);

   MyTimer t = new MyTimer();
   t.Interval = 1000;
   t.Elapsed += delegate { t.Dispose(resetEvent); };

   resetEvent.WaitOne();
}


public class MyTimer : System.Timers.Timer
{
   protected override void Dispose(bool disposing)
   {
       base.Dispose(disposing);
   }

   public virtual void Dispose(WaitHandle handle)
   {
       handle.SafeWaitHandle.Close();
       Dispose();
   }
}

在呼叫 dispose 之前設置一個標誌,並在您的 elapsed 處理程序中檢查此標誌。即使計時器確實觸發了,該標誌也會阻止任何關聯的處理程式碼執行。您可以通過為計時器編寫包裝器來形式化這種模式。

確保您的標誌被標記為 volatile,因為它將被不同的執行緒訪問。

引用自:https://stackoverflow.com/questions/4277044