Semaphore と SemaphoreSlim

System.Threading.Semaphore クラスは、名前付きセマフォ (システム全体) またはローカル セマフォを表します。 これは、Win32 セマフォ オブジェクトの Thin ラッパーです。 Win32 セマフォは、リソースのプールへのアクセスの制御に使用できるカウント セマフォです。

SemaphoreSlim クラスは軽量で高速のセマフォを表しており、非常に短い待機時間が期待されている場合に単一プロセス内で待機のために使用できます。 SemaphoreSlim は、共通言語ランタイム (CLR) により提供される同期プリミティブに可能な限り依存します。 ただし、複数のセマフォでの待機をサポートする必要がある場合は、遅れて初期化されるカーネル ベースの待機ハンドルも提供します。 SemaphoreSlim はキャンセル トークンの使用もサポートしていますが、名前付きセマフォや、同期での待機ハンドルの使用はサポートしていません。

制限されているリソースの管理

スレッドは、WaitOne メソッドを呼び出してセマフォに入ります。このメソッドは WaitHandle クラスから継承されるか (System.Threading.Semaphore オブジェクトの場合)、SemaphoreSlim.Wait メソッドまたは SemaphoreSlim.WaitAsync メソッドから継承されます (SemaphoreSlim オブジェクトの場合)。 呼び出しが戻されると、セマフォのカウントがデクリメントします。 スレッドがエントリを要求し、カウントがゼロの場合、そのスレッドはブロックされます。 スレッドが Semaphore.Release メソッドまたは SemaphoreSlim.Release メソッドを呼び出してセマフォを解放すると、ブロックされたスレッドがセマフォに入ることができるようになります。 ブロックされたスレッドがセマフォに入る順序には、先入れ先出し (FIFO) や後入れ先出し (LIFO) などの決まった順序がありません。

スレッドは、System.Threading.Semaphore オブジェクトの WaitOne メソッドまたは SemaphoreSlim オブジェクトの Wait メソッドを繰り返し呼び出すことで、セマフォに複数回入ることができます。 セマフォを解放するために、スレッドは、Semaphore.Release() メソッド オーバーロードまたは SemaphoreSlim.Release() メソッド オーバーロードを同じ回数呼び出すか、Semaphore.Release(Int32) メソッド オーバーロードまたは SemaphoreSlim.Release(Int32) メソッド オーバーロードを呼び出して、解放するエントリ数を指定します。

セマフォとスレッド ID

この 2 つの種類のセマフォは、WaitOneWaitRelease、および SemaphoreSlim.Release の各メソッドの呼び出しでスレッド ID を適用しません。 たとえば、セマフォの一般的な使用シナリオでは、producer スレッドと consumer スレッドが使用され、一方のスレッドが常にセマフォ カウントをインクリメントし、もう一方のスレッドが常にセマフォ カウントをデクリメントします。

プログラマは、スレッドによるセマフォの解放回数が多くなりすぎないようにする必要があります。 たとえば、セマフォの最大カウントが 2 で、スレッド A とスレッド B が両方ともセマフォに入るとします。 スレッド B がプログラミング エラーのために Release を 2 回呼び出した場合、この呼び出しは両方とも成功します。 セマフォのカウントがいっぱいになっているときに、スレッド A も Release を呼び出すと、SemaphoreFullException がスローされます。

名前付きセマフォ

Windows オペレーティング システムでは、セマフォに名前を付けることができます。 名前付きセマフォはシステム全体でのセマフォです。 つまり、名前付きセマフォは、作成されると、すべてのプロセスのすべてのスレッドで認識されるようになります。 そのため、名前付きセマフォは、プロセスおよびスレッドのアクティビティを同期するために使用できます。

名前を指定するコンストラクターのいずれかを使用して、名前付きシステム セマフォを表す Semaphore オブジェクトを作成できます。

注意

名前付きセマフォはシステム全体でのセマフォであるため、同じ名前付きセマフォを表す複数の Semaphore オブジェクトが存在する可能性があります。 コンストラクターまたは Semaphore.OpenExisting メソッドを呼び出すたびに、新しい Semaphore オブジェクトが作成されます。 同じ名前を繰り返し指定すると、同じ名前付きセマフォを表す複数のオブジェクトが作成されます。

名前付きセマフォを使用する際には注意する必要があります。 システム全体でのセマフォであるため、同じ名前を使用する別のプロセスが予期せずセマフォに入る可能性があります。 同じコンピューター上で実行される悪意のあるコードが、これをサービス拒否攻撃の土台として使用する可能性があります。

アクセス制御セキュリティを使用して、名前付きセマフォを表す Semaphore オブジェクトを保護します。可能であれば System.Security.AccessControl.SemaphoreSecurity オブジェクトを指定するコンストラクターを使用して保護します。 Semaphore.SetAccessControl メソッドを使用してアクセス制御セキュリティを適用することもできますが、この場合、セマフォが作成されてから保護されるまでの間に無防備な時間帯が生じてしまいます。 アクセス制御セキュリティによりセマフォを保護すると、悪意のある攻撃を防ぐことができますが、意図しない名前の競合の問題の解決にはなりません。

関連項目