SemaphoreSlim クラス

定義

リソースまたはリソースのプールに同時にアクセスできるスレッドの数を制限する Semaphore の軽量版を表します。

public ref class SemaphoreSlim : IDisposable
public class SemaphoreSlim : IDisposable
[System.Runtime.InteropServices.ComVisible(false)]
public class SemaphoreSlim : IDisposable
type SemaphoreSlim = class
    interface IDisposable
[<System.Runtime.InteropServices.ComVisible(false)>]
type SemaphoreSlim = class
    interface IDisposable
Public Class SemaphoreSlim
Implements IDisposable
継承
SemaphoreSlim
属性
実装

次の例では、最大 3 つのスレッド数と初期スレッド数が 0 のセマフォを作成します。 この例では、5 つのタスクが開始され、そのすべてがセマフォの待機をブロックします。 メイン スレッドはオーバーロードを Release(Int32) 呼び出してセマフォ数を最大に増やします。これにより、3 つのタスクがセマフォに入ることができます。 セマフォが解放されるたびに、前のセマフォ数が表示されます。 コンソール メッセージはセマフォの使用を追跡します。 シミュレートされた作業間隔は、出力の読み取りを容易にするために、スレッドごとにわずかに増加します。

using System;
using System.Threading;
using System.Threading.Tasks;

public class Example
{
    private static SemaphoreSlim semaphore;
    // A padding interval to make the output more orderly.
    private static int padding;

    public static void Main()
    {
        // Create the semaphore.
        semaphore = new SemaphoreSlim(0, 3);
        Console.WriteLine("{0} tasks can enter the semaphore.",
                          semaphore.CurrentCount);
        Task[] tasks = new Task[5];

        // Create and start five numbered tasks.
        for (int i = 0; i <= 4; i++)
        {
            tasks[i] = Task.Run(() =>
            {
                // Each task begins by requesting the semaphore.
                Console.WriteLine("Task {0} begins and waits for the semaphore.",
                                  Task.CurrentId);
                
                int semaphoreCount;
                semaphore.Wait();
                try
                {
                    Interlocked.Add(ref padding, 100);

                    Console.WriteLine("Task {0} enters the semaphore.", Task.CurrentId);

                    // The task just sleeps for 1+ seconds.
                    Thread.Sleep(1000 + padding);
                }
                finally {
                    semaphoreCount = semaphore.Release();
                }
                Console.WriteLine("Task {0} releases the semaphore; previous count: {1}.",
                                  Task.CurrentId, semaphoreCount);
            });
        }

        // Wait for half a second, to allow all the tasks to start and block.
        Thread.Sleep(500);

        // Restore the semaphore count to its maximum value.
        Console.Write("Main thread calls Release(3) --> ");
        semaphore.Release(3);
        Console.WriteLine("{0} tasks can enter the semaphore.",
                          semaphore.CurrentCount);
        // Main thread waits for the tasks to complete.
        Task.WaitAll(tasks);

        Console.WriteLine("Main thread exits.");
    }
}
// The example displays output like the following:
//       0 tasks can enter the semaphore.
//       Task 1 begins and waits for the semaphore.
//       Task 5 begins and waits for the semaphore.
//       Task 2 begins and waits for the semaphore.
//       Task 4 begins and waits for the semaphore.
//       Task 3 begins and waits for the semaphore.
//       Main thread calls Release(3) --> 3 tasks can enter the semaphore.
//       Task 4 enters the semaphore.
//       Task 1 enters the semaphore.
//       Task 3 enters the semaphore.
//       Task 4 releases the semaphore; previous count: 0.
//       Task 2 enters the semaphore.
//       Task 1 releases the semaphore; previous count: 0.
//       Task 3 releases the semaphore; previous count: 0.
//       Task 5 enters the semaphore.
//       Task 2 releases the semaphore; previous count: 1.
//       Task 5 releases the semaphore; previous count: 2.
//       Main thread exits.
Imports System.Threading
Imports System.Threading.Tasks

Module Example
   Private semaphore As SemaphoreSlim
    ' A padding interval to make the output more orderly.
    Private padding As Integer

   Public Sub Main()
      ' Create the semaphore.
      semaphore = New SemaphoreSlim(0, 3)
      Console.WriteLine("{0} tasks can enter the semaphore.",
                        semaphore.CurrentCount)
      Dim tasks(4) As Task

      ' Create and start five numbered tasks.
      For i As Integer = 0 To 4
         tasks(i) = Task.Run(
            Sub()
               ' Each task begins by requesting the semaphore.
               Console.WriteLine("Task {0} begins and waits for the semaphore.",
                              Task.CurrentId)
               semaphore.Wait()

               Interlocked.Add(padding, 100)

               Console.WriteLine("Task {0} enters the semaphore.", Task.CurrentId)

               ' The task just sleeps for 1+ seconds.
               Thread.Sleep(1000 + padding)

               Console.WriteLine("Task {0} releases the semaphore previous count: {1}.",
                                 Task.CurrentId, semaphore.Release())
            End Sub )
      Next

      ' Wait for half a second, to allow all the tasks to start and block.
      Thread.Sleep(500)

      ' Restore the semaphore count to its maximum value.
      Console.Write("Main thread calls Release(3) --> ")
      semaphore.Release(3)
      Console.WriteLine("{0} tasks can enter the semaphore.",
                        semaphore.CurrentCount)
      ' Main thread waits for the tasks to complete.
      Task.WaitAll(tasks)

      Console.WriteLine("Main thread exits.")
   End Sub
End Module
' The example displays output like the following:
'       0 tasks can enter the semaphore.
'       Task 1 begins and waits for the semaphore.
'       Task 5 begins and waits for the semaphore.
'       Task 2 begins and waits for the semaphore.
'       Task 4 begins and waits for the semaphore.
'       Task 3 begins and waits for the semaphore.
'       Main thread calls Release(3) --> 3 tasks can enter the semaphore.
'       Task 4 enters the semaphore.
'       Task 1 enters the semaphore.
'       Task 3 enters the semaphore.
'       Task 4 releases the semaphore; previous count: 0.
'       Task 2 enters the semaphore.
'       Task 1 releases the semaphore; previous count: 0.
'       Task 3 releases the semaphore; previous count: 0.
'       Task 5 enters the semaphore.
'       Task 2 releases the semaphore; previous count: 1.
'       Task 5 releases the semaphore; previous count: 2.
'       Main thread exits.

注釈

セマフォは、ローカル セマフォと名前付きシステム セマフォの 2 種類です。 ローカル セマフォはアプリケーションに対してローカルであり、システム セマフォはオペレーティング システム全体で表示され、プロセス間の同期に適しています。 これはSemaphoreSlim、Windowsカーネル セマフォをSemaphore使用しないクラスの軽量な代替手段です。 Semaphoreクラスとは異なり、SemaphoreSlimクラスは名前付きシステム セマフォをサポートしていません。 ローカル セマフォとしてのみ使用できます。 この SemaphoreSlim クラスは、1 つのアプリ内での同期に推奨されるセマフォです。

軽量セマフォは、アプリケーションにローカルなリソースのプールへのアクセスを制御します。 セマフォをインスタンス化するときに、セマフォに同時に入ることができるスレッドの最大数を指定できます。 セマフォを同時に入力できるスレッドの初期数も指定します。 これにより、セマフォの数が定義されます。

スレッドがセマフォに入るたびにカウントが減少し、スレッドがセマフォを解放するたびにインクリメントされます。 セマフォに入るために、スレッドはいずれかのオーバーロードをWaitWaitAsync呼び出します。 セマフォを解放するには、オーバーロードの 1 つを Release 呼び出します。 カウントが 0 に達すると、他のスレッドがセマフォを Wait 解放するまで、いずれかのメソッドへの後続の呼び出しがブロックされます。 複数のスレッドがブロックされている場合、FIFO や LIFO など、スレッドがセマフォに入るタイミングを制御する順序は保証されません。

セマフォを使用してリソースを保護するコードの基本的な構造は次のとおりです。

' Enter semaphore by calling one of the Wait or WaitAsync methods.
SemaphoreSlim.Wait()
'
' Execute code protected by the semaphore.
'
SemaphoreSlim.Release()

すべてのスレッドがセマフォを解放すると、セマフォの作成時に指定された最大値がカウントされます。 セマフォの数は、プロパティから CurrentCount 使用できます。

重要

クラスではSemaphoreSlim、スレッド ID またはタスク ID が 、WaitAsyncメソッドへの呼び出しReleaseWait対して強制されません。 さらに、コンストラクターを SemaphoreSlim(Int32) 使用してオブジェクトをインスタンス化する SemaphoreSlim 場合、プロパティは CurrentCount コンストラクターによって設定された値を超えて増加する可能性があります。 呼び出しまたはWaitAsyncメソッドがメソッドの呼び出しWaitRelease適切にペアになるようにするのはプログラマの責任です。

コンストラクター

SemaphoreSlim(Int32)

同時に許可される要求の初期数を指定して、SemaphoreSlim クラスの新しいインスタンスを初期化します。

SemaphoreSlim(Int32, Int32)

同時に許可される要求の初期数および最大数を指定して、SemaphoreSlim クラスの新しいインスタンスを初期化します。

プロパティ

AvailableWaitHandle

セマフォの待機に使用できる WaitHandle を返します。

CurrentCount

SemaphoreSlim オブジェクトに入る、残りのスレッド数を取得します。

メソッド

Dispose()

SemaphoreSlim クラスの現在のインスタンスによって使用されているすべてのリソースを解放します。

Dispose(Boolean)

SemaphoreSlim が使用しているアンマネージド リソースを解放します。オプションとして、マネージド リソースを解放することもできます。

Equals(Object)

指定されたオブジェクトが現在のオブジェクトと等しいかどうかを判断します。

(継承元 Object)
GetHashCode()

既定のハッシュ関数として機能します。

(継承元 Object)
GetType()

現在のインスタンスの Type を取得します。

(継承元 Object)
MemberwiseClone()

現在の Object の簡易コピーを作成します。

(継承元 Object)
Release()

SemaphoreSlim のオブジェクトを一度解放します。

Release(Int32)

指定された回数だけ、SemaphoreSlim オブジェクトを解放します。

ToString()

現在のオブジェクトを表す文字列を返します。

(継承元 Object)
Wait()

SemaphoreSlim に入れるようになるまで、現在のスレッドをブロックします。

Wait(CancellationToken)

SemaphoreSlim を観察すると同時に、CancellationToken に入れるようになるまで、現在のスレッドをブロックします。

Wait(Int32)

タイムアウト値を 32 ビット符号付き整数で指定して、SemaphoreSlim に入れるようになるまで、現在のスレッドをブロックします。

Wait(Int32, CancellationToken)

CancellationToken を観察すると同時に、タイムアウト値を 32 ビット符号付き整数で指定して、SemaphoreSlim に入れるようになるまで、現在のスレッドをブロックします。

Wait(TimeSpan)

TimeSpan を使用してタイムアウトを指定し、SemaphoreSlim に入れるようになるまで、現在のスレッドをブロックします。

Wait(TimeSpan, CancellationToken)

CancellationToken を観察すると同時に、タイムアウトを指定する TimeSpan を使用して、SemaphoreSlim に入れるようになるまで、現在のスレッドをブロックします。

WaitAsync()

SemaphoreSlim に移行するために非同期に待機します。

WaitAsync(CancellationToken)

CancellationToken を観察すると同時に、SemaphoreSlim に移行するために非同期に待機します。

WaitAsync(Int32)

32 ビット符号付き整数を使用して時間間隔を測定しながら、SemaphoreSlim に移行するために非同期に待機します。

WaitAsync(Int32, CancellationToken)

32 ビット符号付き整数を使用して時間間隔を測定しながら、CancellationToken を観察すると同時に、SemaphoreSlim に移行するために非同期に待機します。

WaitAsync(TimeSpan)

TimeSpan を使用して時間間隔を測定しながら、SemaphoreSlim に移行するために非同期に待機します。

WaitAsync(TimeSpan, CancellationToken)

SemaphoreSlim を使用して時間間隔を測定しながら、TimeSpan を観察すると同時に、CancellationToken に移行するために非同期に待機します。

適用対象

スレッド セーフ

パブリックメンバーとプロテクトメンバー SemaphoreSlim はすべてスレッドセーフであり、複数の Dispose()スレッドから同時に使用できます。ただし、例外は、他のすべての操作 SemaphoreSlim が完了した場合にのみ使用する必要があります。

こちらもご覧ください