Поделиться через


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

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

Имя Описание
SemaphoreSlim(Int32, Int32)

Инициализирует новый экземпляр SemaphoreSlim класса, указывая начальное и максимальное количество запросов, которые могут быть предоставлены одновременно.

SemaphoreSlim(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, CancellationToken)

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

Wait(Int32)

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

Wait(TimeSpan, CancellationToken)

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

Wait(TimeSpan)

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

WaitAsync()

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

WaitAsync(CancellationToken)

Асинхронно ожидает ввода SemaphoreSlim, наблюдая за ней CancellationToken.

WaitAsync(Int32, CancellationToken)

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

WaitAsync(Int32)

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

WaitAsync(TimeSpan, CancellationToken)

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

WaitAsync(TimeSpan)

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

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

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

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

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