none
TPL - CancellationToken RRS feed

  • Frage

  • Hallo zusammen,

    ich beschäftige mich zur Zeit mit der TPL und bleibe im wahrsten Sinn des Wortes bei der Verwendung des CancellationTokens bzw. der ThrowIfCancellationRequested-Methode hängen.

    Hier die Deklarationen:

    Private cts As CancellationTokenSource
    Private token As CancellationToken
    Private myTask As task

    Der Task:

    myTask = Task.Factory.StartNew(Sub()
       Do
    	'irgendein Code
    	
            'auf Abbruchanforderung reagieren:
            If token.IsCancellationRequested Then
    		'Auslösen einer Exception
    		token.ThrowIfCancellationRequested()
    	End If
       Loop
    End Sub, token)

    Auslösen der Anforderung zum Task-Abbruch:

    cts.Cancel
    
    'Den Fehler auffangen und anzeigen
    
    Try
       myTask.Wait()
    Catch ex As AggregateException
       For Each v in ex.InnerExceptions
          'Code
       Next
    End Try

    Der Code zum Task-Abbruch befindet sich innerhalb eines Button_Click-Ereignisses. Klicke ich diesen Button an, erhalte ich diese Fehlermeldung bei der Anweisung "token.ThrowIfCancellationRequested()":


    Weshalb taucht diese Fehlermeldung auf, wenn das auslösende Element, das "Wait"-Statement sich in einer Try-/Catch-Fehlerbehandlungsroutine befindet? Meinem Verständnis nach müsste die Exception dadurch doch abgefangen werden?

    Vielen Dank und viele Grüße

    Michael

    Freitag, 18. Juli 2014 12:49

Antworten

Alle Antworten

  • Hallo Michael,

    in dem Fall liegt es daran, dass der Debugger sich vordrängelt, siehe dazu:

    FAQ :: The Debugger does not correctly handle Task exceptions?

    Du solltest Dir auch mal anschauen: Parallel Programming: Task Cancellation

    Ist zwar C#, sollte aber ohne Probleme auf VB übertragbar sein und zeigt einige Möglichkeiten wie man mit Abbrüchen umgehen kann.

    Im übrigen würde ich das CancellationToken nicht als Member Variable speichern, man kann es jederzeit aus der CancellationTokenSource neu erzeugen. Es ist bewusst als leichtgewichtige Struktur angelegt.

    Gruß Elmar

    Freitag, 18. Juli 2014 16:09
    Beantworter
  • Hallo Elmar,

    vielen Dank für die wieder einmal hilfreiche Antwort.

    Wenn Du schreibst, Du würdest das CancellationToken nicht als Member Variable speichern, da man es jederzeit aus der CancellationTokenSource erzeugen kann - wie würde der von mir gepostete Code dann aussehen - sprich, wie erzeuge ich das Token aus der Source?

    Viele Grüße

    Michael

    Montag, 21. Juli 2014 08:04
  • Hallo Michael,

    das CancelToken ist abhängig von CancellationTokenSource und somit würdest Du zwei Variablen zum gleichen Kontext speichern.

    Über CancellationTokenSource kannst Du jederzeit ein Token abrufen, die verweisen alle auf die gleiche Quelle. Für oben zum Beispiel:

            myTask = Task.Factory.StartNew(
                Sub()
                    Dim token = cts.Token ' oder als Methoden Argument
                    Do
                        'irgendein Code
    
                        ' Ein Test wäre doppelt gehoppelt, da ThrowIf genau dies tut
                        token.ThrowIfCancellationRequested()
                    Loop
                End Sub, cts.Token)
    

    Das zusätzliche If kann man sich ebenfalls sparen, denn wie ThrowIf es beschreibt, macht es genau das. Siehe auch: Recommended patterns for CancellationToken

    Dort kommt stellenweise Async / Await zum Einsatz, was man ab VB 2012 bevorzugen sollte, da es doch einiges vereinfacht, sobald auf Thread gewartet werden muss, siehe Asynchrone Programmierung mit Async und Await

    Gruß Elmar

    Montag, 21. Juli 2014 14:13
    Beantworter
  • Ein Elmar, eine Antwort.

    Vielen herzlichen Dank.

    Gruß

    Michael

    Dienstag, 22. Juli 2014 07:33