Compartilhar via


SemaphoreSlim Classe

Definição

Representa uma alternativa leve para Semaphore limitar o número de threads que podem acessar um recurso ou 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 para o máximo, o que permite que três tarefas insiram o semáforo. Cada vez que o semáforo é liberado, a contagem de semáforos anterior é exibida. As 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. É SemaphoreSlim uma alternativa leve à Semaphore classe que não usa semáforos de kernel do Windows. 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 criar uma instância de 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 incrementado 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 atinge zero, chamadas subsequentes para um dos Wait métodos bloqueiam 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 do thread ou da tarefa em chamadas para o método e Release o Wait. WaitAsync 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 ou WaitWaitAsync métodos sejam adequadamente emparelhados com chamadas aos Release métodos.

Construtores

Nome Description
SemaphoreSlim(Int32, Int32)

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

SemaphoreSlim(Int32)

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

Propriedades

Nome Description
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 SemaphoreSlim objeto.

Métodos

Nome Description
Dispose()

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

Dispose(Boolean)

Libera os recursos não gerenciados usados pelo SemaphoreSlime, 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 Objectatual.

(Herdado de Object)
Release()

Libera o SemaphoreSlim objeto uma vez.

Release(Int32)

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

ToString()

Retorna uma cadeia de caracteres que representa o objeto atual.

(Herdado de Object)
Wait()

Bloqueia o thread atual até que ele possa inserir o SemaphoreSlim.

Wait(CancellationToken)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSlim, enquanto observa um CancellationToken.

Wait(Int32, CancellationToken)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSliminteiro com sinal de 32 bits que especifica o tempo limite, enquanto observa um CancellationToken.

Wait(Int32)

Bloqueia o thread atual até que ele possa inserir o SemaphoreSliminteiro com sinal de 32 bits que especifica 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, enquanto observa um CancellationToken.

Wait(TimeSpan)

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

WaitAsync()

Espera de forma assíncrona para entrar no SemaphoreSlim.

WaitAsync(CancellationToken)

Espera assíncronamente para inserir o SemaphoreSlim, enquanto observa um CancellationToken.

WaitAsync(Int32, CancellationToken)

Espera assíncronamente para inserir o SemaphoreSliminteiro com sinal de 32 bits para medir o intervalo de tempo, enquanto observa um CancellationToken.

WaitAsync(Int32)

Espera assíncronamente para inserir o SemaphoreSliminteiro com sinal de 32 bits para medir o intervalo de tempo.

WaitAsync(TimeSpan, CancellationToken)

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

WaitAsync(TimeSpan)

Espera assíncronamente para inserir o SemaphoreSlim, usando um TimeSpan para medir o intervalo de tempo.

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