条件変数
条件変数は、スレッドが特定の条件が発生するまで待機できるようにする同期プリミティブです。 条件変数は、プロセス間で共有できないユーザー モード オブジェクトです。
条件変数を使用すると、スレッドはロックをアトミックに解放し、スリープ状態に入ります。 クリティカル セクションまたはスリム リーダー/ライター (SRW) ロックで使用できます。 条件変数は、待機中のスレッドを "スリープ解除" または "すべてスリープ解除" する操作をサポートします。 スレッドがウェイクされた後、スレッドがスリープ状態になったときに解放されたロックを再取得します。
呼び出し元は 、CONDITION_VARIABLE 構造体を割り当て、 InitializeConditionVariable (構造体を動的に初期化するため) を呼び出すか、構造体変数に定数 CONDITION_VARIABLE_INIT を割り当てる (構造体を静的に初期化する) 方法で初期化する必要があることに注意してください。
Windows Server 2003 および Windows XP: 条件変数はサポートされていません。
条件変数関数を次に示します。
条件変数関数 | 説明 |
---|---|
InitializeConditionVariable | 条件変数を初期化します。 |
SleepConditionVariableCS | 指定した条件変数をスリープ状態にし、指定したクリティカル セクションをアトミック操作として解放します。 |
SleepConditionVariableSRW | 指定した条件変数をスリープ状態にし、指定した SRW ロックをアトミック操作として解放します。 |
WakeAllConditionVariable | 指定した条件変数で待機しているすべてのスレッドをスリープ解除します。 |
WakeConditionVariable | 指定した条件変数で待機している 1 つのスレッドをスリープ解除します。 |
次の擬似コードは、条件変数の一般的な使用パターンを示しています。
CRITICAL_SECTION CritSection;
CONDITION_VARIABLE ConditionVar;
void PerformOperationOnSharedData()
{
EnterCriticalSection(&CritSection);
// Wait until the predicate is TRUE
while( TestPredicate() == FALSE )
{
SleepConditionVariableCS(&ConditionVar, &CritSection, INFINITE);
}
// The data can be changed safely because we own the critical
// section and the predicate is TRUE
ChangeSharedData();
LeaveCriticalSection(&CritSection);
// If necessary, signal the condition variable by calling
// WakeConditionVariable or WakeAllConditionVariable so other
// threads can wake
}
たとえば、リーダー/ライター ロックの実装では、 TestPredicate
関数は現在のロック要求が既存の所有者と互換性があることを確認します。 その場合は、ロックを取得します。それ以外の場合は、スリープ状態にします。 詳細な例については、「 条件変数の使用」を参照してください。
条件変数は、誤ったウェイクアップ (明示的なウェイクアップに関連付けられていないもの) と盗まれたウェイクアップ (別のスレッドが起動スレッドの前に実行を管理) の対象となります。 したがって、スリープ操作が戻った後に述語 (通常 は while ループ内) を再確認する必要があります。
WakeConditionVariable または WakeAllConditionVariable を使用して、条件変数に関連付けられているロックの内部または外部で、他のスレッドをスリープ解除できます。 通常は、他のスレッドをウェイクする前にロックを解除して、コンテキストスイッチの数を減らす方が良いです。
多くの場合、同じロックで複数の条件変数を使用すると便利です。 たとえば、リーダー/ライター ロックの実装では、1 つのクリティカル セクションが使用されますが、リーダーとライターには個別の条件変数が使用される場合があります。
関連トピック