コンテキスト

このドキュメントでは、同時実行ランタイムでのコンテキストの役割について説明します。 スケジューラにアタッチされたスレッドは、実行コンテキストまたは単にコンテキストと呼ばれています。 concurrency::wait 関数と concurrency::Context クラスを使用すると、コンテキストの動作を制御することができます。 指定した時刻に現在のコンテキストを中断するには、wait 関数を使用します。 コンテキストがブロック、ブロック解除、および中断するタイミングをより細かく制御する必要がある場合や、現在のコンテキストをオーバーサブスクライブする場合は、Context クラスを使用します。

ヒント

コンカレンシー ランタイムには既定のスケジューラが用意されているため、アプリケーションにスケジューラを作成する必要はありません。 タスク スケジューラを使用すると、アプリケーションのパフォーマンスを微調整できるため、同時実行ランタイムを初めて使用する場合は、並列パターン ライブラリ (PPL) または非同期エージェント ライブラリから始めることをお勧めします。

wait 関数

concurrency::wait 関数は、指定されたミリ秒間、現在のコンテキストの実行を協調的に中断します。 ランタイムは、中断時間を利用して他のタスクを実行します。 指定された時間が経過すると、ランタイムはコンテキストの実行を再スケジュールします。 そのため、wait 関数は、milliseconds パラメーターに指定された値より長い現在のコンテキストを中断する可能性があります。

milliseconds パラメーターに 0 (ゼロ) を渡した場合は、他のすべてのアクティブなコンテキストに作業を実行する機会が与えられるまで、ランタイムが現在のコンテキストを中断します。 これにより、あるタスクを他のすべてのアクティブなタスクに明け渡すことができます。

wait 関数を使用して現在のコンテキストを中断し、他のコンテキストが実行できるようにする例については、「方法: スケジュール グループを使用して実行順序に影響を与える」を参照してください。

Context クラス

concurrency::Context クラスは、実行コンテキストのプログラミング抽象化を提供し、現在のコンテキストを協調的にブロック、ブロック解除、および中断する機能と、現在のコンテキストをオーバーサブスクライブする機能の 2 つの重要な機能を提供します。

協調ブロッキング

Context クラスを使用すると、現在の実行コンテキストをブロックまたは生成できます。 ブロックや中断は、リソースを使用できないために現在のコンテキストを続行できない場合に便利です。

concurrency::Context::Block メソッドは、現在のコンテキストをブロックします。 ブロックされているコンテキストは、ランタイムが他のタスクを実行できるように、その処理リソースを明け渡します。 concurrency::Context::Unblock メソッドは、ブロックされたコンテキストをブロック解除します。 Context::Unblock メソッドは、Context::Block を呼び出したコンテキストとは異なるコンテキストから呼び出す必要があります。 コンテキストがそれ自体をブロック解除しようとすると、ランタイムが concurrency::context_self_unblock をスローします。

コンテキストを協調的にブロックおよびブロック解除するには、通常、concurrency::Context::CurrentContext を呼び出して、現在のスレッドに関連付けられた Context オブジェクトへのポインターを取得し、結果を保存します。 その後で、Context::Block メソッドを呼び出して、現在のコンテキストをブロックします。 後で、別のコンテキストから Context::Unblock を呼び出して、ブロックされたコンテキストをブロック解除します。

Context::BlockContext::Unblock の呼び出しの各ペアを一致させる必要があります。 Context::Block または Context::Unblock メソッドが他のメソッドの呼び出しと照合せずに連続して呼び出された場合は、ランタイムが concurrency::context_unblock_unbalanced をスローします。 ただし、Context::Unblock を呼び出す前に Context::Block を呼び出す必要はありません。 たとえば、あるコンテキストが、別のコンテキストが同じコンテキストに対して Context::Block を呼び出す前に Context::Unblock を呼び出した場合は、そのコンテキストがブロック解除されたままになります。

concurrency::Context::Yield メソッドは、ランタイムが他のタスクを実行してから、コンテキストの実行を再スケジュールできるように、実行を中断します。 Context::Block メソッドを呼び出しても、ランタイムはコンテキストを再スケジュールしません。

Context::BlockContext::Unblock、および Context::Yield メソッドを使用して協調セマフォ クラスを実装する例については、「方法: Context クラスを使用して協調セマフォを実装する」を参照してください。

オーバーサブスクリプション

既定のスケジューラは、使用可能なハードウェア スレッドと同じ数のスレッドを作成します。 オーバーサブスクリプションを使用して、特定のハードウェア スレッド用の追加のスレッドを作成できます。

計算負荷の高い操作の場合は、追加のオーバーヘッドが発生するため、通常オーバースクリプションではスケーリングしません。 ただし、ディスクやネットワーク接続からのデータの読み取りなど、待機時間が長いタスクの場合は、オーバースクリプションによって一部のアプリケーションの全体的な効率性が向上する可能性があります。

Note

オーバースクリプションは、同時実行ランタイムによって作成されたスレッドからのみ有効にします。 オーバーサブスクリプションは、ランタイムによって作成されなかったスレッド (メイン スレッドを含む) から呼び出された場合には実行されません。

現在のコンテキストでオーバーサブスクリプションを有効にするには、_BeginOversubscription パラメーターを true に設定して concurrency::Context::Oversubscribe メソッドを呼び出します。 同時実行ランタイムによって作成されたスレッドでオーバースクリプションを有効にすると、ランタイムが追加のスレッドを 1 つ作成します。 オーバースクリプションが必要なすべてのタスクが完了したら、_BeginOversubscription パラメーターを false に設定して Context::Oversubscribe を呼び出します。

現在のコンテキストからオーバースクリプションを複数回有効にできますが、有効にした回数と同じ回数無効にする必要があります。 オーバースクリプションは入れ子にすることもできます。つまり、オーバーサブスクリプションを使用する別のタスクによって作成されたタスクもそのコンテキストをオーバーサブスクライブできます。 ただし、入れ子にされたタスクとその親の両方が同じコンテキストに属している場合は、Context::Oversubscribe の最も外側の呼び出しだけが追加のスレッドの作成を引き起こします。

Note

オーバースクリプションが有効になる前に無効になった場合は、ランタイムが concurrency::invalid_oversubscribe_operation をスローします。

オーバースクリプションを使用してネットワーク接続からデータを読み取ることによって発生する待機時間をオフセットする例については、「方法: オーバーサブスクリプションを使用して待機時間を短縮する」を参照してください。

関連項目

タスク スケジューラ
方法: スケジュール グループを使用して実行順序に影響を与える
方法: Context クラスを使用して協調セマフォを実装する
方法: オーバーサブスクリプションを使用して待機時間を短縮する