クリティカル セクション オブジェクト
クリティカル セクション オブジェクト は、ミューテックス オブジェクトによって提供される同期と同様の同期を提供します。ただし、クリティカル セクションは 1 つのプロセスのスレッドでのみ使用できます。 クリティカル セクション オブジェクトをプロセス間で共有することはできません。
イベント、ミューテックス、およびセマフォ オブジェクトは、単一プロセス アプリケーションでも使用できますが、クリティカル セクション オブジェクトは、相互除外同期 (プロセッサ固有のテストおよび設定命令) に対して、より高速で効率的なメカニズムを提供します。 ミューテックス オブジェクトと同様に、クリティカル セクション オブジェクトは一度に 1 つのスレッドのみが所有できるため、共有リソースを同時アクセスから保護するのに役立ちます。 ミューテックス オブジェクトとは異なり、クリティカル セクションが破棄されたかどうかを判断する方法はありません。
Windows Server 2003 Service Pack 1 (SP1) 以降では、重要なセクションを待機しているスレッドは、先着順でクリティカル セクションを取得しません。 この変更により、ほとんどのコードのパフォーマンスが大幅に向上します。 ただし、一部のアプリケーションは先入れ先出し (FIFO) の順序付けに依存しており、現在のバージョンの Windows (たとえば、レート制限機能として重要なセクションを使用しているアプリケーション) でパフォーマンスが低下したり、まったく実行されない場合があります。 コードが正常に動作し続けるには、追加のレベルの同期を追加する必要がある場合があります。 たとえば、プロデューサー スレッドとコンシューマー スレッドがあり、クリティカル セクション オブジェクトを使用して作業を同期しているとします。 2 つのイベント オブジェクトを作成します。1 つは、他のスレッドが続行する準備ができていることを通知するために使用するスレッドごとに 1 つです。 コンシューマー スレッドは、プロデューサーがクリティカル セクションに入る前にイベントを通知するのを待機し、プロデューサー スレッドはコンシューマー スレッドがクリティカル セクションに入る前にそのイベントを通知するのを待機します。 各スレッドがクリティカル セクションを離れると、そのイベントにもう一方のスレッドを解放するよう通知されます。
Windows Server 2003 および Windows XP: 重要なセクションで待機している スレッドが待機キューに追加されます。これらは起こされ、通常はキューに追加された順序でクリティカル セクションを取得します。 ただし、スレッドがこのキューに十分な速度で追加されると、待機している各スレッドを目覚めさせるのに時間がかかるため、パフォーマンスが低下する可能性があります。
プロセスは、クリティカル セクションによって使用されるメモリを割り当てる役割を担います。 通常、これは単に CRITICAL_SECTION型の変数を宣言することによって行われます。 プロセスのスレッドで使用する前に、InitializeCriticalSection または InitializeCriticalSectionAndSpinCount関数使用してクリティカル セクションを初期化します。
スレッドは、EnterCriticalSection または tryEnterCriticalSection関数使用して、クリティカル セクションの所有権を要求します。 LeaveCriticalSection 関数を使用して、クリティカル セクションの所有権を解放します。 クリティカル セクション オブジェクトが現在別のスレッドによって所有されている場合、EnterCriticalSection は所有権を無期限に待機します。 これに対し、ミューテックス オブジェクトを相互除外に使用する場合、待機関数 指定されたタイムアウト間隔を受け入れます。 TryEnterCriticalSection 関数は、呼び出し元のスレッドをブロックせずにクリティカル セクションの入力を試みます。
スレッドがクリティカル セクションを所有している場合、実行をブロックすることなく、EnterCriticalSection または TryEnterCriticalSection追加の呼び出しを行うことができます。 これにより、既に所有している重要なセクションを待機している間にスレッド自体がデッドロックするのを防ぐことができます。 その所有権を解放するには、スレッドがクリティカル セクションに入るたびに、LeaveCriticalSection を 1 回呼び出す必要があります。 待機中のスレッドがクリティカル セクションの所有権を取得する順序については保証されません。
スレッドは、InitializeCriticalSectionAndSpinCount または SetCriticalSectionSpinCount関数使用して、クリティカル セクション オブジェクトのスピンカウントを指定します。 スピンとは、スレッドがロックされている重要なセクションを取得しようとしたときに、スレッドがループに入り、ロックが解放されているかどうかを確認し、ロックが解除されていない場合はスレッドがスリープ状態に移行することを意味します。 単一プロセッサ システムでは、スピン数は無視され、クリティカル セクションのスピン数は 0 (ゼロ) に設定されます。 マルチプロセッサ システムでは、クリティカル セクションが使用できない場合、呼び出し元のスレッドは dwSpinCount 回スピンしてから、クリティカル セクションに関連付けられているセマフォに対して待機操作を実行します。 スピン操作中にクリティカル セクションが解放された場合、呼び出し元のスレッドは待機操作を回避します。
プロセスのすべてのスレッドは、DeleteCriticalSection 関数を使用して、クリティカル セクション オブジェクトの初期化時に割り当てられるシステム リソースを解放できます。 この関数が呼び出されると、クリティカル セクション オブジェクトを同期に使用できません。
クリティカル セクション オブジェクトが所有されている場合、影響を受ける他のスレッドは、EnterCriticalSectionの呼び出しで所有権を待機しているスレッドだけです。 待機していないスレッドは、実行を続行できます。
関連トピック