Critical Section Objects (クリティカル セクション オブジェクト)

クリティカル セクション オブジェクトは、ミューテックス オブジェクトによって提供される同期と同様の同期を提供しますが、クリティカル セクションは 1 つのプロセスのスレッドでのみ使用できます。 重要なセクション オブジェクトをプロセス間で共有することはできません。

イベント、ミューテックス、セマフォ オブジェクトは、単一プロセス アプリケーションでも使用できますが、重要なセクション オブジェクトは、相互排他同期 (プロセッサ固有のテストと設定命令) に対して、少し高速で効率的なメカニズムを提供します。 ミューテックス オブジェクトと同様に、クリティカル セクション オブジェクトは一度に 1 つのスレッドのみが所有できるため、共有リソースを同時アクセスから保護するのに役立ちます。 ミューテックス オブジェクトとは異なり、重要なセクションが破棄されたかどうかを確認する方法はありません。

Windows Server 2003 Service Pack 1 (SP1) 以降では、クリティカル セクションを待機しているスレッドは、先着順でクリティカル セクションを取得しません。 この変更により、ほとんどのコードのパフォーマンスが大幅に向上します。 ただし、一部のアプリケーションは先入れ先出し (FIFO) の順序付けに依存し、現在のバージョンのWindows (たとえば、レートリミッターとして重要なセクションを使用しているアプリケーション) でパフォーマンスが低下したり、まったく実行されない場合があります。 コードが正常に動作し続けるには、同期のレベルを追加する必要がある場合があります。 たとえば、プロデューサー スレッドとコンシューマー スレッドがあり、クリティカル セクション オブジェクトを使用して作業を同期しているとします。 2 つのイベント オブジェクトを作成します。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 の呼び出しで所有権を待機しているスレッドだけです。 待機していないスレッドは、実行を続行できます。

ミューテックス オブジェクト

クリティカル セクション オブジェクトの使用