【ITニュース解説】Mastering Task Cancellation in C#: A Practical Guide with Linked Tokens
2025年09月06日に「Dev.to」が公開したITニュース「Mastering Task Cancellation in C#: A Practical Guide with Linked Tokens」について初心者にもわかりやすいように丁寧に解説しています。
ITニュース概要
C#で非同期タスクのキャンセル処理を実装する方法を紹介。`CancellationToken`でタスク停止を指示し、`CreateLinkedTokenSource()`で複数のキャンセル要因(ユーザー操作、タイムアウト)を統合する。サンプルコードでは、ファイルダウンロードをシミュレートし、ユーザーによるキャンセルとタイムアウトによるキャンセルを実装。タスクの応答性、リソース効率、堅牢性を向上させる。
ITニュース解説
この記事では、C#におけるタスクのキャンセル処理について解説する。特に、CancellationTokenの使用方法と、複数のキャンセルソースを組み合わせるCreateLinkedTokenSource()の活用に焦点を当てる。
まず、タスクのキャンセルがなぜ重要なのかを説明する。バックグラウンドで実行される可能性のあるタスク(例えば、ファイルのダウンロード)を考えてみよう。ユーザーがアプリを閉じたり、ダウンロードをキャンセルしたりした場合、キャンセル機能がなければ、タスクは完了するまでリソースを消費し続ける。CancellationTokenは、タスクを停止させるための連携メカニズムを提供する。
記事では、具体的なデモを通してキャンセル処理を理解する。デモの要件は以下の通り。5つのタスクをファイルダウンロードに見立てて開始する。各ダウンロードは約5〜10秒かかるようにする。コンソールに進捗状況を表示する。ユーザーが'c'キーを押すことで、すべてのダウンロードをキャンセルできるようにする。また、タスクの一つがタイムアウトした場合、自動的にキャンセルされるようにする。すべてのタスクが正常に完了した場合、成功メッセージを表示する。
メインプログラムでは、まず、ユーザーがキーを押すことでキャンセルを要求できるように、別のタスクを起動する。externalCancellationというCancellationTokenSourceを使用し、ユーザーが'c'キーを押すと、Cancel()メソッドを呼び出してすべてのタスクをキャンセルする。
次に、5つのタスクを起動し、それぞれのタスクでBackgroundDownloadWorkerクラスのDoWorkメソッドを実行する。DoWorkメソッドは、外部からのキャンセル要求を受け取るためのexternalCancellationTokenを引数として受け取る。
タスクの実行中、OperationCanceledExceptionが発生した場合、例外をキャッチし、ユーザーによるキャンセルか、タイムアウトなどの内部的な理由によるキャンセルかを区別してコンソールに表示する。
BackgroundDownloadWorkerクラスは、ダウンロード処理をシミュレートする。このクラスには、internalCancellation、internalCancellationToken、_workerIndex、_timerというフィールドがある。internalCancellationは、ワーカー自身がタイムアウトなどでキャンセルできるようにするためのCancellationTokenSource。internalCancellationTokenは、internalCancellationから取得したCancellationToken。_workerIndexは、ワーカーのインデックスを保持し、主にログ出力に使用する。_timerは、タイムアウトを監視するためのSystem.Threading.Timer。
コンストラクタでは、ワーカーのインデックスを設定し、オプションのtimerTimeoutパラメータに基づいてタイマーを作成する。タイムアウトが指定された場合、タイマーが作成され、タイムアウトが発生するとTimeoutActionメソッドが呼び出される。
DoWorkメソッドは、外部からのキャンセルトークンを受け取り、内部的なキャンセルと外部からのキャンセルを組み合わせた、リンクされたキャンセルトークンを作成する。CancellationTokenSource.CreateLinkedTokenSource(internalCancellationToken, externalCancellationToken)を使用することで、どちらかのトークンがキャンセルされた場合、タスク全体がキャンセルされる。
DoInternalWorkメソッドは、ダウンロード処理をシミュレートする。ループ処理を行い、cancellationToken.ThrowIfCancellationRequested()を呼び出すことで、キャンセルが要求されているかどうかをチェックする。キャンセルが要求されている場合、OperationCanceledExceptionがスローされる。
TimeoutActionメソッドは、タイマーが満了したときに呼び出される。このメソッドは、internalCancellation.Cancel()を呼び出してワーカーをキャンセルし、タイマーを破棄してリソースを解放する。
複数のキャンセルソースを組み合わせることで、アプリケーションはより柔軟に対応できるようになる。例えば、ユーザーの操作によるキャンセルと、タイムアウトなどの内部的なイベントによるキャンセルを同時に処理できる。CancellationTokenSource.CreateLinkedTokenSource()を使用することで、簡単に複数のキャンセルソースを組み合わせることができる。
記事では、2つのテストケースを紹介する。1つ目は、ユーザーが'c'キーを押してキャンセルする場合。2つ目は、プログラムが中断されずに正常に完了する場合。それぞれのシナリオで、期待される動作を確認することで、キャンセル処理の理解を深めることができる。
まとめとして、CancellationTokenを使用することで、長時間実行されるタスクを停止させることができる。また、複数のキャンセルソースを組み合わせることで、アプリケーションはより堅牢になる。このパターンは、HTTPリクエストのキャンセル、データベースクエリの停止、並列バックグラウンドジョブの管理など、さまざまな場面で役立つ。キャンセル処理を適切に実装することで、アプリケーションの応答性、リソース効率、および信頼性を向上させることができる。