SemaphoreSlim Classe

Definição

Representa uma alternativa leve para Semaphore que limita o número de threads que podem acessar um recurso ou um pool de recursos simultaneamente.

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
Herança
SemaphoreSlim
Atributos
Implementações

Exemplos

O exemplo a seguir cria um semáforo com uma contagem máxima de três threads e uma contagem inicial de zero threads. O exemplo inicia cinco tarefas, todas as quais bloqueiam a espera pelo semáforo. O thread principal chama a Release(Int32) sobrecarga para aumentar a contagem de semáforos ao máximo, o que permite que três tarefas insiram o semáforo. Cada vez que o semáforo é lançado, a contagem de semáforos anterior é exibida. Mensagens de console rastreiam o uso de semáforo. O intervalo de trabalho simulado é aumentado ligeiramente para cada thread para facilitar a leitura da saída.

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.

Comentários

Semáforos são de dois tipos: semáforos locais e semáforos do sistema nomeados. Os semáforos locais são locais para um aplicativo, os semáforos do sistema são visíveis em todo o sistema operacional e são adequados para sincronização entre processos. A SemaphoreSlim é uma alternativa leve à Semaphore classe que não usa Windows semáforos kernel. Ao contrário da Semaphore classe, a SemaphoreSlim classe não dá suporte a semáforos nomeados do sistema. Você pode usá-lo apenas como semáforo local. A SemaphoreSlim classe é o semáforo recomendado para sincronização em um único aplicativo.

Um semáforo leve controla o acesso a um pool de recursos que é local para seu aplicativo. Ao instanciar um semáforo, você pode especificar o número máximo de threads que podem inserir o semáforo simultaneamente. Você também especifica o número inicial de threads que podem inserir o semáforo simultaneamente. Isso define a contagem do semáforo.

A contagem é decrementada sempre que um thread entra no semáforo e incrementada sempre que um thread libera o semáforo. Para inserir o semáforo, um thread chama uma das Wait sobrecargas ou WaitAsync sobrecargas. Para liberar o semáforo, ele chama uma das Release sobrecargas. Quando a contagem atingir zero, as chamadas subsequentes para um dos Wait métodos são bloqueadas até que outros threads liberem o semáforo. Se vários threads forem bloqueados, não haverá nenhuma ordem garantida, como FIFO ou LIFO, que controla quando os threads entram no semáforo.

A estrutura básica para código que usa um semáforo para proteger recursos é:

' Enter semaphore by calling one of the Wait or WaitAsync methods.
SemaphoreSlim.Wait()
'
' Execute code protected by the semaphore.
'
SemaphoreSlim.Release()

Quando todos os threads liberam o semáforo, a contagem está no valor máximo especificado quando o semáforo foi criado. A contagem do semáforo está disponível na CurrentCount propriedade.

Importante

A SemaphoreSlim classe não impõe a identidade de thread ou tarefa em chamadas e WaitWaitAsyncRelease métodos. Além disso, se o SemaphoreSlim(Int32) construtor for usado para instanciar o SemaphoreSlim objeto, a CurrentCount propriedade poderá aumentar além do valor definido pelo construtor. É responsabilidade do programador garantir que as chamadas Wait ou WaitAsync métodos sejam adequadamente emparelhados com chamadas aos Release métodos.

Construtores

SemaphoreSlim(Int32)

Inicializa uma nova instância da classe SemaphoreSlim, especificando o número inicial de solicitações que podem ser concedidas simultaneamente.

SemaphoreSlim(Int32, Int32)

Inicializa uma nova instância da classe SemaphoreSlim, especificando o número inicial e o máximo de solicitações que podem ser concedidas simultaneamente.

Propriedades

AvailableWaitHandle

Retorna um WaitHandle que pode ser usado para aguardar o semáforo.

CurrentCount

Obtém o número de threads restantes que podem inserir o objeto SemaphoreSlim.

Métodos

Dispose()

Libera todos os recursos usados pela instância atual da classe SemaphoreSlim.

Dispose(Boolean)

Libera os recursos não gerenciados usados pelo SemaphoreSlim e opcionalmente libera os recursos gerenciados.

Equals(Object)

Determina se o objeto especificado é igual ao objeto atual.

(Herdado de Object)
GetHashCode()

Serve como a função de hash padrão.

(Herdado de Object)
GetType()

Obtém o Type da instância atual.

(Herdado de Object)
MemberwiseClone()

Cria uma cópia superficial do Object atual.

(Herdado de Object)
Release()

Libera o objeto SemaphoreSlim uma única vez.

Release(Int32)

Libera o objeto SemaphoreSlim um número de vezes especificado.

ToString()

Retorna uma cadeia de caracteres que representa o objeto atual.

(Herdado de Object)
Wait()

Bloqueia o thread atual até que o SemaphoreSlim possa ser inserido.

Wait(CancellationToken)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSlim, enquanto observar uma CancellationToken.

Wait(Int32)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSlim, usando um inteiro com sinal de 32 bits que especifica o tempo limite.

Wait(Int32, CancellationToken)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSlim, usando um inteiro com sinal de 32 bits que especifica o tempo limite, observando simultaneamente um CancellationToken.

Wait(TimeSpan)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSlim, usando um TimeSpan para especificar o tempo limite.

Wait(TimeSpan, CancellationToken)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSlim, usando um TimeSpan que especifica o tempo limite, observando simultaneamente um CancellationToken.

WaitAsync()

Espera assincronamente para inserir o SemaphoreSlim.

WaitAsync(CancellationToken)

Espera assincronamente para inserir o SemaphoreSlim, ao observar um CancellationToken.

WaitAsync(Int32)

Aguarda de forma assíncrona para inserir o SemaphoreSlim, usando um inteiro com sinal de 32 bits para medir o intervalo de tempo.

WaitAsync(Int32, CancellationToken)

Espera assincronamente para inserir o SemaphoreSlim, usando um inteiro com sinal de 32 bits para medir o intervalo de tempo, enquanto observa um CancellationToken.

WaitAsync(TimeSpan)

Espera assincronamente para inserir o SemaphoreSlim, usando um TimeSpan para medir o intervalo de tempo.

WaitAsync(TimeSpan, CancellationToken)

Espera assincronamente para inserir o SemaphoreSlim, usando um TimeSpan para medir o intervalo de tempo, enquanto observa um CancellationToken.

Aplica-se a

Acesso thread-safe

Todos os membros públicos e protegidos SemaphoreSlim são thread-safe e podem ser usados simultaneamente de vários threads, com exceção de Dispose(), que devem ser usados somente quando todas as outras operações no SemaphoreSlim tiverem sido concluídas.

Confira também