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
Атрибуты
Реализации

Примеры

В следующем примере создается семафор с максимальным числом трех потоков и начальным числом нулевых потоков. В примере запускается пять задач, все из которых блокируют ожидание семафора. Основной поток вызывает перегрузку Release(Int32) , чтобы увеличить количество семафоров до максимального значения, что позволяет трем задачам войти в семафор. При каждом освобождении семафора отображается предыдущее число семафоров. Сообщения консоли отслеживают использование семафора. Имитированный рабочий интервал немного увеличивается для каждого потока, чтобы упростить чтение выходных данных.

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.

Комментарии

Семафоры бывают двух типов: локальные семафоры и именованные системные семафоры. Локальные семафоры являются локальными для приложения, системные семафоры видны всей операционной системе и подходят для межпроцессной синхронизации. SemaphoreSlim— это упрощенная альтернатива классуSemaphore, который не использует семафоры ядра Windows. Semaphore В отличие от класса, SemaphoreSlim класс не поддерживает именованные системные семафоры. Его можно использовать только в качестве локального семафора. Класс SemaphoreSlim является рекомендуемой семафором для синхронизации в одном приложении.

Упрощенный семафор управляет доступом к пулу ресурсов, который является локальным для вашего приложения. При создании экземпляра семафора можно указать максимальное количество потоков, которые могут одновременно входить в семафор. Вы также указываете начальное количество потоков, которые могут одновременно входить в семафор. Это определяет количество семафоров.

Число уменьшается каждый раз, когда поток входит в семафор, и увеличивается каждый раз, когда поток освобождает семафор. Чтобы ввести семафор, поток вызывает одну из Wait перегрузок или WaitAsync . Чтобы освободить семафор, он вызывает одну из Release перегрузок. Когда число достигает нуля, последующие вызовы одного из 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 не применяет удостоверение потока или задачи при вызовах Waitметодов , WaitAsyncи Release . Кроме того, если SemaphoreSlim(Int32) конструктор используется для создания экземпляра SemaphoreSlim объекта, CurrentCount свойство может увеличиться за пределы значения, заданного конструктором. Программист отвечает за то, чтобы вызовы Wait методов или WaitAsync были соответствующим образом связаны с вызовами Release методов.

Конструкторы

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)

Блокирует текущий поток до тех пор, пока он не сможет войти в SemaphoreSlim, используя 32-разрядное целое число со знаком, которое определяет время ожидания.

Wait(Int32, CancellationToken)

Блокирует текущий поток до тех пор, пока он не сможет войти в SemaphoreSlim, используя 32-разрядное целое число со знаком, которое определяет время ожидания, и контролирует токен CancellationToken.

Wait(TimeSpan)

Блокирует текущий поток до тех пор, пока он не сможет войти в SemaphoreSlim, используя значение TimeSpan для определения времени ожидания.

Wait(TimeSpan, CancellationToken)

Блокирует текущий поток до тех пор, пока он не сможет войти в SemaphoreSlim, используя значение TimeSpan, которое определяет время ожидания, и контролирует токен CancellationToken.

WaitAsync()

Асинхронно ожидает входа в SemaphoreSlim.

WaitAsync(CancellationToken)

Асинхронно ожидает входа в SemaphoreSlim, контролируя CancellationToken.

WaitAsync(Int32)

Асинхронно ожидает входа в SemaphoreSlim, используя 32-разрядное целое число со знаком для измерения интервала времени.

WaitAsync(Int32, CancellationToken)

Асинхронно ожидает входа в SemaphoreSlim, используя 32-разрядное целое число со знаком для измерения интервала времени, контролируя CancellationToken.

WaitAsync(TimeSpan)

Асинхронно ожидает входа в SemaphoreSlim, используя TimeSpan для измерения интервала времени.

WaitAsync(TimeSpan, CancellationToken)

Асинхронно ожидает входа в SemaphoreSlim, используя TimeSpan для измерения интервала времени и контролируя CancellationToken.

Применяется к

Потокобезопасность

Все открытые и защищенные члены SemaphoreSlim являются потокобезопасными и могут использоваться одновременно из нескольких потоков, за исключением Dispose(), которые необходимо использовать только после завершения всех остальных операций SemaphoreSlim с .

См. также раздел