次の方法で共有


コンテキスト

更新 : 2010 年 7 月

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

ヒント

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

wait 関数

Concurrency::wait 関数は、指定した時間 (ミリ秒単位) だけ現在のコンテキストの実行を協調的に譲渡します。 ランタイムは、譲渡された時間を使用して他のタスクを実行します。 指定した時間が経過すると、ランタイムは、コンテキストの実行を再スケジュールします。 したがって、wait 関数は、milliseconds パラメーターで指定した値よりも長く現在のコンテキストを中断させる場合があります。

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

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

Context クラス

Concurrency::Context クラスは、実行コンテキストのプログラミング概念と 2 つの重要な機能を提供します。1 つは現在のコンテキストを協調的にブロック、ブロック解除、および譲渡する機能、もう 1 つは現在のコンテキストをオーバーサブスクライブする機能です。

協調ブロッキング

Context クラスを使用すると、現在の実行コンテキストをブロックまたは譲渡できます。 ブロックまたは譲渡する機能は、リソースを使用できないことが原因で現在のコンテキストを続行できない場合に有用です。

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

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

Context::Block の呼び出しと Context::Unblock の呼び出しはペアとしてそれぞれ対応させる必要があります。 Context::Block メソッドまたは Context::Unblock メソッドを協調的に呼び出し、対応する他方のメソッドを呼び出さないと、ランタイムは Concurrency::context_unblock_unbalanced をスローします。 ただし、Context::Unblock を呼び出す前に Context::Block を呼び出す必要はありません。 たとえば、あるコンテキストが Context::Unblock を呼び出し、その後別のコンテキストがその同じコンテキストに対し Context::Block を呼び出した場合、そのコンテキストはブロック解除されたままとなります。

Concurrency::Context::Yield メソッドは実行を譲渡するため、ランタイムは他のタスクを実行でき、その後、コンテキストの実行を再スケジュールできます。 Context::Block メソッドを呼び出した場合、ランタイムはコンテキストを再スケジュールしません。

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

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

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

計算量が非常に多い処理の場合、オーバーサブスクリプションではオーバーヘッドが増えるため、通常は効率は向上されません。 ただし、ディスクやネットワーク接続からのデータの読み取りなど、待機時間が非常に長いタスクの場合、オーバーサブスクリプションにより一部のアプリケーションについて全体的に効率を向上させることができます。

注意

オーバーサブスクリプションは、同時実行ランタイムによって作成された、UMS 以外のスレッドからのみ有効にしてください。 ランタイムにより作成されたものではないスレッド (メイン スレッドを含みます) からオーバーサブスクリプションを呼び出しても効果はありません。 さらに、UMS スレッドを使用してタスクをスケジュールするコンテキストからオーバーサブスクリプションを呼び出しても効果はありません。これは、UMS スレッドはスケジューラを有効にしてブロッキング操作の下でリソースを完全に使用するためです。

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

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

注意

オーバーサブスクリプションが有効化される前に無効化されると、ランタイムは Concurrency::invalid_oversubscribe_operation をスローします。

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

参照

その他の技術情報

タスク スケジューラ (同時実行ランタイム)

方法: スケジュール グループを使用して実行順序に影響を与える

方法: Context クラスを使用して協調セマフォを実装する

方法: オーバーサブスクリプションを使用して待機時間を短縮する

履歴の変更

日付

履歴

理由

2010 年 7 月

内容を再構成。

情報の拡充