SemaphoreSlim Classe

Definição

Representa uma alternativa leve que Semaphore limita o número de threads que podem aceder a um recurso ou conjunto de recursos em simultâneo.

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 seguinte 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 bloqueadas à espera do semáforo. O thread principal chama a Release(Int32) sobrecarga para aumentar o número de semáforos ao máximo, permitindo que três tarefas entrem no semáforo. Cada vez que o semáforo é libertado, é apresentada a contagem anterior de semáforos. As mensagens de consola acompanham o uso de semáforos. O intervalo de trabalho simulado é ligeiramente aumentado 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.

Observações

Os semáforos são de dois tipos: semáforos locais e semáforos de sistemas nomeados. Os semáforos locais são locais para uma aplicação, os semáforos do sistema são visíveis por todo o sistema operativo e são adequados para sincronização entre processos. O SemaphoreSlim é uma alternativa leve à classe Semaphore que não utiliza semáforos Windows kernel. Ao contrário da Semaphore classe, esta SemaphoreSlim não suporta semáforos de sistemas nomeados. Podes usá-lo apenas como semáforo local. A SemaphoreSlim classe é o semáforo recomendado para sincronização dentro de uma única aplicação.

Um semáforo leve controla o acesso a um conjunto de recursos local para a sua aplicação. Quando instancias um semáforo, podes especificar o número máximo de threads que podem entrar no semáforo em simultâneo. Também especificas o número inicial de threads que podem entrar no semáforo em simultâneo. Isto define a contagem do semáforo.

A contagem é decrementada cada vez que um fio entra no semáforo, e incrementada cada vez que um fio liberta o semáforo. Para entrar no semáforo, um fio chama uma das Wait sobrecargas de ou WaitAsync . Para libertar o semáforo, chama uma das Release sobrecargas. Quando a contagem atinge zero, chamadas subsequentes a um dos Wait métodos bloqueiam-se até que outros threads libertem o semáforo. Se múltiplos threads estiverem bloqueados, não existe uma ordem garantida, como FIFO ou LIFO, que controle quando os threads entram no semáforo.

A estrutura básica para código que utiliza 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 todas as threads libertam 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 identidade de thread ou tarefa nas chamadas aos Waitmétodos , WaitAsync, e Release . Além disso, se o SemaphoreSlim(Int32) construtor for usado para instanciar o SemaphoreSlim objeto, a CurrentCount propriedade pode aumentar para além do valor definido pelo construtor. É responsabilidade do programador garantir que as chamadas para Wait ou WaitAsync métodos são adequadamente associadas a chamadas para Release métodos.

Construtores

Name Description
SemaphoreSlim(Int32, Int32)

Inicializa uma nova instância da SemaphoreSlim classe, especificando o número inicial e máximo de pedidos que podem ser concedidos simultaneamente.

SemaphoreSlim(Int32)

Inicializa uma nova instância da SemaphoreSlim classe, especificando o número inicial de pedidos que podem ser concedidos simultaneamente.

Propriedades

Name Description
AvailableWaitHandle

Devolve um WaitHandle que pode ser usado para esperar pelo semáforo.

CurrentCount

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

Métodos

Name Description
Dispose()

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

Dispose(Boolean)

Liberta os recursos não geridos usados pelo SemaphoreSlim, e opcionalmente liberta os recursos geridos.

Equals(Object)

Determina se o objeto especificado é igual ao objeto atual.

(Herdado de Object)
GetHashCode()

Serve como função de hash predefinida.

(Herdado de Object)
GetType()

Obtém o Type da instância atual.

(Herdado de Object)
MemberwiseClone()

Cria uma cópia superficial do atual Object.

(Herdado de Object)
Release()

Liberta o SemaphoreSlim objeto uma vez.

Release(Int32)

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

ToString()

Devolve uma cadeia que representa o objeto atual.

(Herdado de Object)
Wait()

Bloqueia o thread atual até que este possa entrar no SemaphoreSlimarquivo .

Wait(CancellationToken)

Bloqueia o fio atual até que este possa entrar no SemaphoreSlim, enquanto observa um CancellationToken.

Wait(Int32, CancellationToken)

Bloqueia o thread atual até que este possa entrar no SemaphoreSlim, usando um inteiro assinado de 32 bits que especifica o timeout, enquanto observa um CancellationToken.

Wait(Int32)

Bloqueia a thread atual até que esta possa introduzir o SemaphoreSlim, usando um inteiro assinado de 32 bits que especifica o timeout.

Wait(TimeSpan, CancellationToken)

Bloqueia o thread atual até que possa entrar no SemaphoreSlim, usando a TimeSpan que especifica o timeout, enquanto observa um CancellationToken.

Wait(TimeSpan)

Bloqueia o thread atual até que este possa entrar no SemaphoreSlim, usando a TimeSpan para especificar o timeout.

WaitAsync()

Espera assíncronamente para introduzir o SemaphoreSlim.

WaitAsync(CancellationToken)

Aguarda assíncronamente para introduzir o SemaphoreSlim, enquanto observa um CancellationToken.

WaitAsync(Int32, CancellationToken)

Assíncronamente espera para introduzir o SemaphoreSlim, usando um inteiro com sinal de 32 bits para medir o intervalo de tempo, enquanto observa um CancellationToken.

WaitAsync(Int32)

Aguarda assíncronamente para introduzir o SemaphoreSlim, usando um inteiro assinado de 32 bits para medir o intervalo de tempo.

WaitAsync(TimeSpan, CancellationToken)

Assíncronamente espera para introduzir o SemaphoreSlim, usando a TimeSpan para medir o intervalo de tempo, enquanto observa um CancellationToken.

WaitAsync(TimeSpan)

Aguarda assíncronamente para introduzir o SemaphoreSlim, usando a TimeSpan para medir o intervalo de tempo.

Aplica-se a

Segurança de Thread

Todos os membros públicos e protegidos de SemaphoreSlim são seguros para threads e podem ser usados em simultâneo a partir de múltiplas threads, com exceção de Dispose(), que só deve ser usado quando todas as outras operações no SemaphoreSlim tiverem concluído.

Ver também