いろいろ備忘録日記

主に .NET と Python絡みのメモを公開しています。

.NET クラスライブラリ探訪-049 (System.Threading.SemaphoreSlim(1))(セマフォ, 軽量版, CancellationToken, .NET 4.0)


今回は、SemaphoreSlimクラスについて。
SemaphoreSlimクラスは、.NET 4.0からSystem.Threading名前空間に追加されたクラスです。
従来から存在していたSemaphoreクラスの計量版という位置づけになります。


セマフォは、リソースに同時にアクセスするスレッド数を制限する場合に利用します。
たとえば、データが詰まっているキューやスタックやリストがあるとして、そこから値を取り出して
処理するスレッドがNあるとします。キューやスタックやリストに対して一度にアクセスできるスレッド数を制限する
場合などに利用したりします。


利用方法もSemaphoreクラスと同じです。
ただし、従来のSemaphoreクラスの場合、WaitOneメソッドだったものが
SemaphoreSlimクラスでは、Waitメソッドになっています。


また、このクラスも以前の記事で記述したCountdownEventやBarrierと同じく
キャンセルトークンを受け付けるWaitメソッドを持っています。
キャンセルトークンを利用した版については、次回記述します。


以下、サンプルです。

    #region SemaphoreSlimSamples-01
    /// <summary>
    /// SemaphoreSlimクラスについてのサンプルです。
    /// </summary>
    /// <remarks>
    /// SemaphoreSlimクラスは、.NET 4.0から追加されたクラスです。
    /// 従来から存在していたSemaphoreクラスの軽量版となります。
    /// </remarks>
    public class SemaphoreSlimSamples01 : IExecutable
    {
        public void Execute()
        {
            //
            // SemaphoreSlimクラスは、Semaphoreクラスの軽量版として
            // .NET 4.0から追加されたクラスである。
            //
            // Semaphoreは、リソースに同時にアクセス出来るスレッドの数を制限するために利用される。
            //
            // 機能的には、Semaphoreクラスと大差ないが以下の機能が追加されている。
            //     キャンセルトークンを受け付けるWaitメソッドのオーバーロードが存在する。
            // キャンセルトークンを受け付けるWaitメソッドに関しては、CountdownEventクラスやBarrierクラス
            // と利用方法は同じである。
            //
            // 尚、元々のSemaphoreクラスでは、WaitOneメソッドだったものが
            // SemaphoreSlimクラスでは、Waitメソッドという名前に変わっている。
            //
            
            //
            // Waitメソッドの利用.
            // 
            // Waitメソッドは、入ることが出来た場合はTrueを返す。
            // 既に上限までスレッドが入っている場合はFalseが返却される。
            // (つまりブロックされる。)
            //
            // 引数無しのWaitメソッドは、入ることが出来るまでブロックされるメソッドとなる。
            // 結果をboolで受け取る場合は、Int32を引数にとるWaitメソッドを利用する。
            // 0を指定すると即結果が返ってくる。-1を指定すると無制限に待つ。
            // (引数無しのWaitメソッドと同じ。)
            //
            // SemaphoreSlimでは、AvailableWaitHandleプロパティよりWaitHandleを取得することが出来る。
            // ただし、このWaitHandleは、SemaphoreSlim本体とは連携しているわけでは無い。
            // なので、このWaitHandle経由でWaitOneを実行しても、SemaphoreSlim側のカウントは変化しないので注意。
            //
            using (SemaphoreSlim semaphore = new SemaphoreSlim(2))
            {
                // 現在Semaphoreに入ることが可能なスレッド数を表示
                Console.WriteLine("CurrentCount={0}", semaphore.CurrentCount);
                
                // 1つ目
                Console.WriteLine("1つ目のWait={0}", semaphore.Wait(0));
                // 2つ目
                Console.WriteLine("2つ目のWait={0}", semaphore.Wait(0));
                
                // 現在Semaphoreに入ることが可能なスレッド数を表示
                Console.WriteLine("CurrentCount={0}", semaphore.CurrentCount);
                
                // 3つ目
                // 現在Releaseしている数は0なので、入ることが出来ない。
                // (Falseが返却される)
                Console.WriteLine("3つ目のWait={0}", semaphore.Wait(0));
                
                // 1つリリースして、枠を空ける.
                semaphore.Release();
                
                // 現在Semaphoreに入ることが可能なスレッド数を表示
                Console.WriteLine("CurrentCount={0}", semaphore.CurrentCount);
                
                // 再度、3つ目
                // 今度は、枠が空いているので入ることが出来る。
                Console.WriteLine("3つ目のWait={0}", semaphore.Wait(0));
                
                // 現在Semaphoreに入ることが可能なスレッド数を表示
                Console.WriteLine("CurrentCount={0}", semaphore.CurrentCount);
                
                semaphore.Release();
                semaphore.Release();

                // 現在Semaphoreに入ることが可能なスレッド数を表示
                Console.WriteLine("CurrentCount={0}", semaphore.CurrentCount);
            }
        }
    }
    #endregion


実行結果は以下のようになります。

  CurrentCount=2
  1つ目のWait=True
  2つ目のWait=True
  CurrentCount=0
  3つ目のWait=False
  CurrentCount=1
  3つ目のWait=True
  CurrentCount=0
  CurrentCount=2


================================
過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。