タスクを実行した際、途中でキャンセルしたいことがあります。その際の方法を記載します。

Taskクラス によるタスクキャンセルは、CancellationTokenSourceクラスを使用します。

タスクキャンセル要求は、CancellationTokenSource.Cancel()メソッドを実行します。

これによりキャンセルフラグが立ち、このフラグを参照することによりキャンセル処理を実行します。

ThrowIfCancellationRequested()によるキャンセル方法

オペレーション側プログラム

Dim cts As CancellationTokenSource

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    cts = New CancellationTokenSource()    
    Try
        Dim t = ActionAsync(cts.Token)          'タスクの実行
        Await t                                 '非同期的に完了待ち
    Catch ex As OperationCanceledException
        MessageBox.Show("キャンセルされました")
    End Try
End Sub

Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    cts.Cancel()        'タスクのキャンセル要求
End Sub

タスク側プログラム(ThrowIfCancellationRequestedメソッド抜け出し)

Async Function ActionAsync(token As CancellationToken) As Task(Of Boolean)
    Dim result As Boolean = Await Task.Run(
         Function() As Boolean
             For i As Integer = 0 To 100
                 token.ThrowIfCancellationRequested()           'キャンセル時の処理
                 Thread.Sleep(1000)
             Next
             Return True
         End Function
    )

    MessageBox.Show("タスク終了")
    Return result
End Function

CancellationToken構造体のThrowIfCancellationRequested()メソッドで、キャンセルフラグをチェックします。

また、実際のキャンセルフラグは、CancellationToken.IsCancellationRequestedプロパティに設定されていて

このフラグが立ったらタスク側は、OperationCanceledException例外をスローするように作成します。

キャンセルフラグの例外スローのコードは、以下のコードのようになります。

If (token.IsCancellationRequested) Then
    Throw New OperationCanceledException(token)
End If

上記を一文で書けるようにメソッドが用意されています。

token.ThrowIfCancellationRequested()

 

例外のスローではない IsCancellationRequestedでのキャンセル抜け出し

ThrowIfCancellationRequested()での抜け出しは、 例外スローするので、上に記載したコードではキャンセルの際、MessageBox.Show(“タスク終了”)実行されません。

そこで、IsCancellationRequestedを参照して抜け出すようにします。

タスク側プログラム(IsCancellationRequestedプロパティ抜け出し)

Async Function ActionAsync(token As CancellationToken) As Task(Of Task)
    Dim result As Task = Task.Run(
         Sub()
             While True
                 If (token.IsCancellationRequested) Then     'キャンセル時の処理
                    Exit While
                 End If
                 Thread.Sleep(1000)
             End While
         End Sub
    )
    Await result

    MessageBox.Show("タスク終了")
    Return result
End Function