2015-04-21 12 views
8

Ich sehe diesen Code vor mir, und ich bin verdächtig:Ist Code, der CancellationTokenSource entlastet, während die Aufgaben abgebrochen werden, korrekt?

CancellationTokenSource _cts; 

public void Dispose(); 
{ 
    _cts.Cancel(); 
    _cts.Dispose(); 
    _task.Wait(); //wait for the task to be canceled!? 
} 

Ist es sicher _cts.Dispose() direkt nach dem Abbrechen anrufen? Würden die zugrunde liegenden Ressourcen der CancellationTokenSource, die für die abgebrochene Aufgabe benötigt werden, nicht erfolgreich auf die CancellationToken warten, wenn sie dies wünschen?

Antwort

7

Ist es sicher, _cts.Dispose() direkt nach dem Abbrechen aufzurufen?

Um das zu wissen, müssen wir verstehen, was passiert, wenn wir eine CancellationTokenSource abbrechen.

Wenn Sie eine CancellationTokenSource abbrechen, ruft sie alle über die CancellationToken registrierten Rückrufe auf, die über die CancellationToken.Register()-Methode einen Verweis auf ihre übergeordnete Quelle enthalten.

Wenn Sie jetzt ein CTS entsorgen, wird versucht, alle verknüpften Rückrufnummern, die registriert wurden, vom Token zu entfernen. Wenn es gerade ausgeführt wird, wird gewartet, bis der Delegat abgeschlossen ist.

Das bedeutet, dass, obwohl Sie Ihre CTS entsorgt haben, das Objekt immer noch vom Token referenziert wird. Daher ist es immer noch nicht zum Sammeln geeignet.

Jetzt ist bei CancellationToken.IsCancellationRequested sehen lassen:

public bool IsCancellationRequested 
{ 
    get 
    { 
     return m_source != null && m_source.IsCancellationRequested; 
    } 
} 

Das bedeutet, dass während angeordnet, nachgeben true, um die Löschung zu überprüfen. Dies bedeutet, dass es für Sie sicher ist, auf den Abschluss der Aufgaben nach dem Aufruf von dispose zu warten.

Als eine Randnotiz, wenn Sie (aus irgendeinem Grund) versuchen, ein Token übergeben über sie ist CancelledTokenSource, werden Sie eine ObjectDisposedException treffen.

Edit:

Zwei Dinge, die ich hinzufügen möchten. Lassen Sie mich zunächst sagen, dass ich diesen Ansatz nicht empfehle. Es sollte für einige Codeausführungspfade funktionieren, aber nicht für alle. CancellationTokenSource sollte normalerweise nur entsorgt werden, wenn Sie seine WaitHandle Eigenschaft verwenden. Ansonsten ist es in Ordnung, es dem GC zu überlassen, die Reinigung durchzuführen. Aber da dies eine Frage des Geschmacks ist, können Sie wählen, was Sie wollen. Ich würde sicherlich empfehlen, nur zu entsorgen, wenn Sie sicher sind, dass die Aufgabe die Stornierungsanfrage eingehalten hat.

Nach der Verwendung von WaitHandle, wird es entsorgt und nulled sobald Sie entsorgen, so dass es wird nicht erreichbar sein.

+1

Aber IsCancellationRequested ist nicht das einzige Szenario, um richtig zu kümmern? Was ist mit WaitHandle? –

+0

'WaitHandle' wird geschlossen, wenn die Entsorgung ausgeführt wird. Ich bin mir nicht sicher, ob 'WaitHandle' ein häufiger Anwendungsfall ist. Ich füge das meiner Antwort hinzu. –

+0

@Tim Ich habe eine wichtige Änderung zu meiner Antwort hinzugefügt. Obwohl das, was du versuchst, * möglich * ist, würde ich es auf jeden Fall nicht empfehlen. –