はじめに
今回はSemaphoreSlim
というリソースに同時にアクセスできるスレッドの数を制限できるクラスについて紹介したいと思います。
概要
SemaphoreSlim
はリソースに同時にアクセスできるスレッド数を制限することができます。例えばテストコードで、同時アクセスした場合にのみ不具合が起きることの確認に使えたりできます。
リソースまたはリソースのプールに同時にアクセスできるスレッドの数を制限する Semaphore の軽量版を表します。
使い方
SemaphoreSlim.Wait
かSemaphore.WaitAsync
で各スレッドの処理をブロックし、Semaphore.Release
を実行して処理を開始させます。
// Dictionaryはスレッドセーフではない Dictionary<string, int> dictionary = new Dictionary<string, int>(); const int Count = 4; var tks = new Task[Count]; // 同時に許可される要求の初期数が0、最大数がCount(=4)に設定する var semaphore = new SemaphoreSlim(0, Count); // Dictionaryにて同時アクセスするとエラーを出力されることを確認する // SemaphoreSlimを利用してヒット率を上げている tks[0] = Task.Run(() => { semaphore.Wait(); dictionary["Sample"] = 0; }); tks[1] = Task.Run(() => { semaphore.Wait(); dictionary["Sample"] = 1; }); tks[2] = Task.Run(() => { semaphore.Wait(); dictionary["Sample"] = 2; }); tks[3] = Task.Run(() => { semaphore.Wait(); dictionary["Sample"] = 3; }); // semaphore.Waitまで辿り着くまで待つ Thread.Sleep(500); // dictionaryへのアクセスを全てのスレッドで開始する semaphore.Release(Count); // 全てのTaskが終わるまで待つ // 同時アクセスした場合 : Unhandled exception. System.AggregateException: One or more errors occurred. (Operations that change non-concurrent collections must have exclusive access. A concurrent update was performed on this collection and corrupted its state. The collection's state is no longer correct.) ... Task.WaitAll(tks);
タイムアウトやCancellationToken
SemaphoreSlim.Wait
の引数にタイムアウト時間やCancellationToken
を渡したりもできます。
- Wait(TimeSpan, CancellationToken)
- Wait(Int32, CancellationToken)
- Wait(TimeSpan)
- Wait(Int32)
- Wait()
- Wait(CancellationToken)
- WaitAsync()
- WaitAsync(CancellationToken)
- WaitAsync(Int32)
- WaitAsync(Int32, CancellationToken)
- WaitAsync(TimeSpan)
- WaitAsync(TimeSpan, CancellationToken)
SemaphoreSlim.Wait メソッド (System.Threading) | Microsoft Learn