2010-11-25 9 views
9

Wenn Sie einen "raw" .net-Timer absetzen, können Sie einen Warte-Handle übergeben, der aufgerufen wird, sobald der Win32-Timer zerstört wurde, und Sie können davon ausgehen, dass Ihr Rückruf nicht aufgerufen wird. (Und der Timer wird vom GC als "tot" betrachtet)Wie kann ich einen System.Timers.Timer sicher entsorgen?

Wie mache ich das mit einem System.Timers.Timer?

Antwort

0

Da System.Timers.Timer und System.Windows.Forms.Timer beide das ThreadPool verwenden, hat es kein Handle zu einem Betriebssystem-Timer, so dass keine native Timer-Ressource entsorgt wird - nur ein abgeschlossener Thread . Ich bin mir nicht sicher, ob Sie einen Thread erfassen können, der vom ThreadPool recycelt wird, aber ich könnte mich irren.

Sie könnten vielleicht Ihre eigene Rolle (ich habe nicht getestet, und einen Manual in Entsorgen nehmen könnte nützlicher sein):

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(); 
    } 
} 
+0

Ich denke, das Ereignis System.Timers.Timer Disposed wird ausgelöst, sobald es die System.Threading.Timer Dispose-Methode aufgerufen hat. –

+0

@Ian Das Ereignis wird in 'Component.Dispose (disposing)' aufgerufen, so dass Sie das WaitHandle vor dem Aufruf von base.Dispose() signalisieren und das benutzerdefinierte Dispose (WaitHandle) verwenden, nach dem es ausgelöst werden soll. –

3

Stellen Sie eine Flagge, bevor Sie verfügen rufen, und überprüfen Sie diese Flagge in Ihr abgelaufener Handler. Selbst wenn der Timer ausgelöst wird, verhindert das Flag, dass ein zugehöriger Handler-Code ausgeführt wird. Sie könnten dieses Muster formalisieren, indem Sie einen Wrapper für den Timer schreiben.

Stellen Sie sicher, dass Ihre Flagge als flüchtig markiert ist, da auf sie von verschiedenen Threads zugegriffen wird.

+0

Flüchtige ist nicht gut genug, verwenden Sie eine MRE oder Interlocked. –

+0

@Hans, wenn das volatile-Flag vor dem Aufruf von dispose gesetzt ist, wird ein Timer-Thread es sehen, wenn ein nachfolgendes abgelaufenes Ereignis auftritt. Was ist das Problem, das Sie hier sehen? –

+0

Überprüfen Sie die Dokumentation für Thread.MemoryBarrier –