xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

TPL入門 (14) - タスクの状態

タスクは、生成の開始からタスクスケジューラーへの登録、タスクの実行、完了など、自身のライフサイクルが現在どのような状態にあるかを事細かに把握しています。また、タスクインスタンス毎に割り当てられる一意のIDも保持しています。今回は、これらタスクの内部状態について見ていきます。

タスクのライフサイクル

タスクのライフサイクルは、Taskクラスの読み取り専用プロパティであるStatusプロパティに問い合わせることで取得できます。取得できるTaskStatus列挙体は次のようになっています。

説明
Created タスクは明示的に生成されましたが、まだスケジューラーへの登録はされていません。(= Startメソッドは呼び出されていません)
WaitingForActivation タスクはContinueWith、ContinueWhenAll、FromAsyncメソッドなどにより暗黙的に生成され、すでに実行をスケジューリングされています。
WaitingToRun タスクはスケジューリングされていますが、まだ実行されていません。
Running タスクは現在実行中です。
WaitingForChildrenToComplete タスクの完了していますが関連付けられている子タスクが完了していないため、その完了を待機しています。
RanToCompletion タスクは正常に完了しました。
Canceled タスクはスケジューラーによって実行を取り消されたか、実行中にキャンセルされました。
Faulted タスクはハンドルされない例外が発生したため異常終了しました。

タスクの最終状態としては、RanToCompletion、Canceled、Faultedのいずれかになります。利用可能性の高いこれらの値をより便利に利用できるよう、TaskクラスにIsCompletedIsCanceledIsFaultedプロパティが提供されています。IsCompletedはStatusプロパティがRanToCompletion、Canceled、Faultedのいずれかのときにtrueを返すので注意が必要です。また、IsFaultedプロパティがtrueの場合はTask.Exceptionプロパティはnull以外を返します。

以前、タスクの継続で紹介した、「成功時のみ継続、キャンセル時のみ継続、エラー時のみ継続」は、これらの最終状態に依存していたことが理解できたかと思います。

タスクIDとVisual Studioのデバッガー

各タスクインスタンスには自身を表す一意のIDが割り振られます。このタスクIDは、読み取り専用のTask.Idプロパティで取得することができます。タスクIDはインスタンス生成時に0に初期化され、初めてIdプロパティを呼び出したときに一意なIDが割り当てられます。タスクIDは1から始まり、IDが割り振られるごとに1ずつインクリメントされていきます。また、コード上でIdプロパティを呼び出していなくても、Visual Studioのデバッガー上でタスクIDが表示されるだけでも割り当てられます。以下にVisual Studioのデバッガー画面を示します。

ParallelTask

上図ではタスクが2つあり、それぞれIDに1、2が割り振られています。また、ID = 2のタスクは実行中ですが、ID = 1のタスクはスケジューリングされているものの実行されておらず、実行を待機していることも分かります。その他、Visual Studioのデバッガーではタスクをより視覚的に解析することも可能になっています。(下図参照)

ParallelStack_Task

ParallelStack_Thread

次回予告

今回はタスクの内部状態について触れました。ライフサイクルなどについて知ることで、タスクがどのように動作しているかをより理解できたかと思います。最終回となる次回は、タスク上でUIコンポーネントを操作する方法について見ていきたいと思います。