Task④
タスクのキャンセル
タスクに渡したラムダ式内でOperationCanceledExceptionをスローすることでタスクをキャンセルできます。
キャンセルされたタスクのTask.StatusはCanceledになります。
var task = Task.Run(() => throw new OperationCanceledException()); try { // タスクは即時キャンセルされるわけでなく、終了を待機する必要があります task.Wait(); } catch (AggregateException) { } finally { // 出力結果は「task status : Canceled」になります Console.WriteLine($"task status : {task.Status}"); }
CancellationToken
CancellationTokenSource・CencellationTokenを使用することで、外部からタスクのキャンセルをコントロールできます。
var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; var task = Task.Run( () => { while (!token.IsCancellationRequested) { Thread.Sleep(200); Console.WriteLine($"processing..."); } }); tokenSource.CancelAfter(1000); try { task.Wait(); } catch (AggregateException) { } finally { Console.WriteLine($"task status : {task.Status}"); }
CancellationTokenSource.Cancel()・CancellationTokenSource.CancelAfter()を実行することで、CancellationTokenSource.Tokenから取得されたトークン及びそのコピーにキャンセルが通知されます。
キャンセルが通知された後、CancellationTokenSource.IsCancellationRequested・CancellationToken.IsCancellationRequestedの値がTrueになるため、
タスクに渡したラムダ式内で上記プロパティ値をモニターし、Trueの場合に終了するような仕組みを組み込むことで、外部からタスクをキャンセルすることができます。
ただし、この方法はフラグで終了判定を行っているに過ぎないため、Task.StatusはRanToCompletionになります。
Task.StatusをCanceledにしたい場合、OperationCanceledExceptionをスローすることで実現できます。
上記サンプルのケースでは適当なローカル変数でも代用可能なので、CancellationTokenのメリットが薄いですが、タスク内で他クラスのメソッドを呼ぶなど、メソッド外に制御が移る場合は有用です。
呼び出し先に順次CancellationTokenを渡していくことで、すべてのメソッドでキャンセル状態をモニターできるようになります。
また、タスクにCancellationTokenを渡すことで、もう少し細かな制御が可能になります。
var tokenSource = new CancellationTokenSource(); var token = tokenSource.Token; var task = Task.Run( () => { while (true) { token.ThrowIfCancellationRequested(); Thread.Sleep(200); Console.WriteLine($"processing..."); } }, token); tokenSource.CancelAfter(1000); try { task.Wait(); } catch (AggregateException) { } finally { Console.WriteLine($"task status : {task.Status}"); }
CancellationToken.ThrowIfCancellationRequested()はOperationCanceledExceptionをスローします。
また、以下条件を満たす場合にTask.StatusをCanceledにし、満たさない場合はFaultedにします。
- CancellationToken.IsCancellationRequestedがTrue
- 自身とタスクに渡されたトークンが同一
ちなみに、上記サンプルでCancelAfter()のパラメーターを0にした場合、即時キャンセル通知が行われます。
タスク実行開始前であればラムダ式は評価されずに終了し、Task.StatusはCenceledとなります。