System.Threading.ThreadPool クラスは、システムによって管理されるワーカー スレッドのプールをアプリケーションに提供し、スレッド管理ではなくアプリケーション タスクに集中できるようにします。 バックグラウンド処理を必要とする短いタスクがある場合、マネージド スレッド プールは複数のスレッドを利用する簡単な方法です。 スレッド プールスレッドで非同期タスクを実行する Task オブジェクトと Task<TResult> オブジェクトを作成できるため、Framework 4 以降ではスレッド プールの使用が大幅に容易になります。
.NET では、 タスク並列ライブラリ (TPL) 操作、非同期 I/O 完了、 タイマー コールバック、登録された待機操作、デリゲートを使用した非同期メソッド呼び出し、 System.Net ソケット接続など、多くの目的でスレッド プール スレッドが使用されます。
スレッド プールの特徴
スレッド プール スレッドは バックグラウンド スレッドです。 各スレッドは、既定のスタック サイズを使用し、既定の優先順位で実行され、マルチスレッド アパートメント内にあります。 スレッド プール内のスレッドがタスクを完了すると、待機中のスレッドのキューに返されます。 この時点から再利用できます。 この再利用により、アプリケーションはタスクごとに新しいスレッドを作成するコストを回避できます。
プロセスごとにスレッド プールは 1 つだけあります。
スレッド プールのスレッドでの例外
スレッド プール スレッドの未処理の例外によってプロセスが終了します。 このルールには次の 3 つの例外があります。
- System.Threading.ThreadAbortException が呼び出されたため、スレッド プールのスレッドに Thread.Abort がスローされる。
- アプリケーション ドメインがアンロードされるため、スレッド プールのスレッドに System.AppDomainUnloadedException がスローされる。
- 共通言語ランタイムまたはホスト プロセスによってスレッドが終了します。
詳細については、「 マネージド スレッドの例外」を参照してください。
スレッド プールのスレッドの最大数
スレッド プールにキューに登録できる操作の数は、使用可能なメモリによってのみ制限されます。 ただし、スレッド プールでは、プロセスで同時にアクティブにできるスレッドの数が制限されます。 すべてのスレッド プール スレッドがビジー状態の場合、実行するスレッドが使用可能になるまで、追加の作業項目がキューに入れられます。 プロセスのスレッド プールの既定のサイズは、仮想アドレス空間のサイズなど、いくつかの要因によって異なります。 プロセスは、 ThreadPool.GetMaxThreads メソッドを呼び出してスレッドの数を決定できます。
ThreadPool.GetMaxThreadsメソッドとThreadPool.SetMaxThreadsメソッドを使用して、スレッドの最大数を制御できます。
注
共通言語ランタイムをホストするコードは、 ICorThreadpool::CorSetMaxThreads
メソッドを使用してサイズを設定できます。
スレッド プールの最小値
スレッド プールは、カテゴリごとに指定された最小値に達するまで、新しいワーカー スレッドまたは I/O 完了スレッドをオンデマンドで提供します。 ThreadPool.GetMinThreadsメソッドを使用して、これらの最小値を取得できます。
注
需要が低い場合、スレッド プール スレッドの実際の数が最小値を下回る可能性があります。
最小値に達すると、スレッド プールは追加のスレッドを作成するか、一部のタスクが完了するまで待機できます。 スレッド プールは、スループットを最適化するためにワーカー スレッドを作成および破棄します。これは、時間単位で完了するタスクの数として定義されます。 使用可能なリソースを最適に使用できないスレッドが少なすぎるのに対し、スレッドの数が多すぎるとリソースの競合が増加する可能性があります。
注意事項
ThreadPool.SetMinThreads メソッドを使用して、アイドル状態のスレッドの最小数を増やすことができます。 ただし、これらの値を不必要に増やすと、パフォーマンスの問題が発生する可能性があります。 同時に開始するタスクが多すぎると、すべてのタスクが遅いように見える可能性があります。 ほとんどの場合、スレッド プールは、スレッドを割り当てる独自のアルゴリズムでパフォーマンスが向上します。
スレッド プールの使用
スレッド プールを使用する最も簡単な方法は、 タスク並列ライブラリ (TPL) を使用することです。 既定では、 Task や Task<TResult> などの TPL 型は、スレッド プール スレッドを使用してタスクを実行します。
また、マネージド コードから ThreadPool.QueueUserWorkItem を呼び出し (またはアンマネージド コードから ICorThreadpool::CorQueueUserWorkItem
)、タスクを実行するメソッドを表す System.Threading.WaitCallback デリゲートを渡すことで、スレッド プールを使用することもできます。
スレッド プールを使用するもう 1 つの方法は、ThreadPool.RegisterWaitForSingleObject メソッドを使用して待機操作に関連する作業項目をキューに入れ、シグナル通知時またはタイムアウト時にSystem.Threading.WaitHandleデリゲートによって表されるメソッドを呼び出すSystem.Threading.WaitOrTimerCallbackを渡すことです。 スレッド プール スレッドは、コールバック メソッドを呼び出すために使用されます。
例については、参照先の API ページを確認してください。
セキュリティ チェックのスキップ
スレッド プールには、 ThreadPool.UnsafeQueueUserWorkItem メソッドと ThreadPool.UnsafeRegisterWaitForSingleObject メソッドも用意されています。 これらのメソッドは、呼び出し元のスタックが、キューに登録されたタスクの実行中に実行されるセキュリティ チェックとは無関係であると確信している場合にのみ使用します。 ThreadPool.QueueUserWorkItem と ThreadPool.RegisterWaitForSingleObject は両方とも呼び出し元のスタックをキャプチャします。このスタックは、スレッドがタスクの実行を開始したときにスレッド プール スレッドのスタックにマージされます。 セキュリティ チェックが必要な場合は、スタック全体をチェックする必要があります。 このチェックは安全性を提供しますが、パフォーマンス コストも発生します。
スレッド プールのスレッドを使用しない場合
スレッド プール スレッドを使用する代わりに、独自のスレッドを作成して管理するのが適切なシナリオがいくつかあります。
- フォアグラウンド スレッドが必要です。
- スレッドに特定の優先順位が必要です。
- 長時間にわたってスレッドがブロックされるタスクがあります。 スレッド プールにはスレッドの最大数があるため、多数のブロックされたスレッド プール スレッドによってタスクが開始できなくなる可能性があります。
- スレッドをシングルスレッド アパートメント内に配置する必要がある場合。 すべての ThreadPool スレッドはマルチスレッド アパートメント内にあります。
- スレッドに関連付けられた安定した ID を持っているか、スレッドをタスク専用にする必要があります。
こちらも参照ください
.NET