1

Ich dachte, dass das CancellationToken/CancellationTokenSource-System ein wenig wie C++ volatile bool bFlagCancelled funktionierte, was bedeutet, dass die Stornierung seitens der Aufgabe freiwillig ist und auf die Aufgabe selbst angewiesen ist, von Zeit zu Zeit zu überprüfen, ob es abgebrochen wird und eine Ausnahme auslöst entweder explizit oder durch Aufruf ThrowIfCancellationRequested().Kann eine TPL-Task, die nicht prüft, ob sie abgebrochen wurde, trotzdem abgebrochen werden?

Aber wenn ich Cancel sofort nach StartNew() aufrufen, stoppt die Aufgabe, und Aufruf Wait() löst eine TaskCanceledException.

Zum Beispiel für diesen Code:

CancellationTokenSource source = new CancellationTokenSource(); 
CancellationToken token = source.Token; 
Task task = Task.Factory.StartNew(
    () => 
    { 
     Console.WriteLine("start sleep"); 
     Thread.Sleep(1000); 
     Console.WriteLine("sleep ended"); 
    } 
    , token); 
// Thread.Sleep(1); 
source.Cancel(); 
Console.WriteLine("start wait"); 
task.Wait(); 
Console.WriteLine("wait ended"); 

ich diese Ausgabe:

start wait 
Exception: System.AggregateException: One or more errors occurred. ---> System.Threading.Tasks.TaskCanceledException: A task was canceled.

Aber wenn ich // Thread.Sleep(1); Kommentar-, dann die Verhaltensänderungen und ich diese Ausgabe:

start sleep 
start wait 
sleep ended 
wait ended

Jetzt dachte ich, vielleicht ist das, weil task.Start() noch nicht aufgerufen wurde, bu t so weit ich es verstehe, StartNew() ruft task.Start() vor dem Zurückgeben - das ist, warum es nicht die Synchronisierungskosten hat und ist gegenüber dem Erstellen einer und Aufruf task.Start() selbst empfohlen.

Also dann bedeutet das in manchen Situationen, dass eine Aufgabe spontan abgebrochen wird, auch ohne das Abbruchzeichen zu prüfen. Ist dies die einzige Situation, in der dies geschieht, oder gibt es weitere Szenarien, in denen dies geschieht?

Antwort

1

Task.Factory.StartNew plant die Aufgabe vor der Rückkehr, aber es bedeutet nicht, dass die Aufgabe tatsächlich ausgeführt wurde. Es gibt also noch Platz zum Abbrechen der Aufgabe, wenn die TaskScheduler dies akzeptiert (intern wird die Methode TaskScheduler.TryDequeue aufgerufen. Die Aufgabe kann als abgebrochen markiert werden, wenn sie wahr zurückgibt).

+0

Danke für die Antwort. Gibt es andere Situationen, in denen dies passieren kann, oder ist dies die einzige? – sashoalm

+1

@ashoalm Immer wenn der Task noch nicht auf 'Running' umgestellt wurde. Wenn Sie zum Beispiel 'ContinueWith' für eine Aufgabe aufrufen und diese Aufgabe abgebrochen wird, wird die Fortsetzung ebenfalls abgebrochen. –

+0

Nochmals vielen Dank. Ich habe gerade http://stackoverflow.com/a/10444108/492336 gefunden, wo sie erklären, dass das Übergeben von 'token' an' StartNew' speziell dieses Verhalten ermöglicht und das Token nicht wirklich an 'StartNew()' übergeben hat gleicher Effekt wie das Auskommentieren von '// Sleep (1)'. – sashoalm

Verwandte Themen