【C#】【非同期】セマフォ(Semaphore / SemaphoreSlim)

■ はじめに

 * 以下の関連記事のC#版。
Java】【非同期】セマフォ(Semaphore)
https://blogs.yahoo.co.jp/dk521123/34264650.html

セマフォ(Semaphore)とは?

 * 以下の関連記事を参照のこと
【非同期】非同期・スレッドに関する用語
https://blogs.yahoo.co.jp/dk521123/37076571.html

C# でのセマフォ

 * System.Threading.Semaphore / SemaphoreSlim クラスが用意されている

  => SemaphoreSlim(.NET4.0以降) は、Semaphore の軽量版(ってAPI仕様に書いてある)
System.Threading.Semaphore
https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.semaphore?view=netframework-4.8
System.Threading.SemaphoreSlim
https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.semaphoreslim?view=netframework-4.8

主なメソッド

Semaphore.WaitOne() / SemaphoreSlim.Wait()
 * シグナルを受け取るまで現在のスレッドをブロック
https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.waithandle.waitone?view=netframework-4.8#System_Threading_WaitHandle_WaitOne
Semaphore.Release() / SemaphoreSlim.Release()
 * セマフォから出て、前のカウントを返す
https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.semaphore.release?view=netframework-4.8#System_Threading_Semaphore_Release

■ サンプル

using System;
using System.Threading;
using System.Windows.Forms;

namespace SampleForm
{
  public partial class Form1 : Form
  {
    //セマフォ
    //スレッドの同時実効数を設定。この場合初期実行数1, 最大実効数5, 名前付き(260 文字以内)
    // https://docs.microsoft.com/ja-jp/dotnet/api/system.threading.semaphore.-ctor?redirectedfrom=MSDN&view=netframework-4.8#System_Threading_Semaphore__ctor_System_Int32_System_Int32_System_String_
    private Semaphore semaphore;

    public Form1()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      this.semaphore = new Semaphore(1, 5, "Demo");

      for (int i = 1; i <= 5; i++)
      {
        Thread thread = new Thread(new ParameterizedThreadStart(this.Worker));
        thread.Start(i);
      }

      Thread.Sleep(500);

      Console.WriteLine("Main thread calls Release(3).");
      this.semaphore.Release(3);

      Console.WriteLine("Main thread exits.");
    }

    private void Worker(object threadNo)
    {
      Console.WriteLine("Thread {0} begins and waits for the semaphore.", threadNo);
      this.semaphore.WaitOne();

      Console.WriteLine("Thread {0} enters the semaphore.", threadNo);

      Thread.Sleep(1000);

      Console.WriteLine("Thread {0} releases the semaphore.", threadNo);
      Console.WriteLine("Thread {0} previous semaphore count: {1}",
          threadNo, this.semaphore.Release());
    }
  }
}

出力結果

Thread 1 begins and waits for the semaphore.
Thread 1 enters the semaphore.
Thread 3 begins and waits for the semaphore.
Thread 2 begins and waits for the semaphore.
Thread 4 begins and waits for the semaphore.
Thread 5 begins and waits for the semaphore.
Main thread calls Release(3).
Main thread exits.
Thread 2 enters the semaphore.
Thread 4 enters the semaphore.
Thread 3 enters the semaphore.
Thread 1 releases the semaphore.
Thread 1 previous semaphore count: 0
Thread 5 enters the semaphore.
スレッド 0x10ec はコード 0 (0x0) で終了しました。
Thread 2 releases the semaphore.
Thread 2 previous semaphore count: 0
スレッド 0x277c はコード 0 (0x0) で終了しました。
Thread 4 releases the semaphore.
Thread 3 releases the semaphore.
Thread 3 previous semaphore count: 2
Thread 4 previous semaphore count: 1
スレッド 0x2cd8 はコード 0 (0x0) で終了しました。
スレッド 0xf0 はコード 0 (0x0) で終了しました。
Thread 5 releases the semaphore.
Thread 5 previous semaphore count: 3
スレッド 0x2960 はコード 0 (0x0) で終了しました。


関連記事

java

Java】【非同期】セマフォ(Semaphore)
https://blogs.yahoo.co.jp/dk521123/34264650.html

その他

【非同期】非同期・スレッドに関する用語
https://blogs.yahoo.co.jp/dk521123/37076571.html