Semaphore e SemaphoreSlimSemaphore and SemaphoreSlim

A classe System.Threading.Semaphore representa um sinal com nome (em todo o sistema) ou local.The System.Threading.Semaphore class represents a named (systemwide) or local semaphore. É um wrapper fino em torno do objeto de sinal Win32.It is a thin wrapper around the Win32 semaphore object. Sinais do Win32 são contagem de sinais que podem ser usadas para controlar o acesso a um pool de recursos.Win32 semaphores are counting semaphores, which can be used to control access to a pool of resources.

A classe SemaphoreSlim representa um sinal leve e rápido que pode ser usado para aguardar por um único processo quando forem esperados tempos de espera muito curtos.The SemaphoreSlim class represents a lightweight, fast semaphore that can be used for waiting within a single process when wait times are expected to be very short. SemaphoreSlim conta com o máximo possível em primitivos de sincronização fornecidos pelo Common Language Runtime (CLR).SemaphoreSlim relies as much as possible on synchronization primitives provided by the common language runtime (CLR). No entanto, fornece também identificadores de espera baseados no kernel inicializados lentamente, conforme necessário para dar suporte à espera de vários sinais.However, it also provides lazily initialized, kernel-based wait handles as necessary to support waiting on multiple semaphores. SemaphoreSlim oferece suporte também ao uso de tokens de cancelamento, mas não oferece suporte a sinais com nome ou ao uso de um identificador de espera para sincronização.SemaphoreSlim also supports the use of cancellation tokens, but it does not support named semaphores or the use of a wait handle for synchronization.

Gerenciando um recurso limitadoManaging a Limited Resource

Os threads inserem o sinal chamando o método WaitOne, que é herdado da classe WaitHandle, no caso de um objeto System.Threading.Semaphore ou o método SemaphoreSlim.Wait ou SemaphoreSlim.WaitAsync, no caso de um objeto SemaphoreSlim.Threads enter the semaphore by calling the WaitOne method, which is inherited from the WaitHandle class, in the case of a System.Threading.Semaphore object, or the SemaphoreSlim.Wait or SemaphoreSlim.WaitAsync method, in the case of a SemaphoreSlim object. Quando a chamada é retornada, a contagem no sinal é reduzida.When the call returns, the count on the semaphore is decremented. Quando um thread solicita entrada e a contagem é zero, o thread é bloqueado.When a thread requests entry and the count is zero, the thread blocks. À medida que os threads liberam o sinal chamando o método Semaphore.Release ou SemaphoreSlim.Release, os threads bloqueados têm permissão para entrar.As threads release the semaphore by calling the Semaphore.Release or SemaphoreSlim.Release method, blocked threads are allowed to enter. Não há uma ordem garantida, como primeiro a entrar, primeiro a sair (PEPS) ou último a entrar, primeiro a sair (UEPS) para threads bloqueados para inserir o sinal.There is no guaranteed order, such as first-in, first-out (FIFO) or last-in, first-out (LIFO), for blocked threads to enter the semaphore.

Um thread pode inserir o sinal várias vezes chamando o método System.Threading.Semaphore do objeto WaitOne ou o método SemaphoreSlim do objeto Wait repetidas vezes.A thread can enter the semaphore multiple times by calling the System.Threading.Semaphore object's WaitOne method or the SemaphoreSlim object's Wait method repeatedly. Para liberar o sinal, o thread pode chamar a sobrecarga do método Semaphore.Release() ou SemaphoreSlim.Release() o mesmo número de vezes ou chamar a sobrecarga do método Semaphore.Release(Int32) ou SemaphoreSlim.Release(Int32) e especificar o número de entradas a ser liberado.To release the semaphore, the thread can either call the Semaphore.Release() or SemaphoreSlim.Release() method overload the same number of times, or call the Semaphore.Release(Int32) or SemaphoreSlim.Release(Int32) method overload and specify the number of entries to be released.

Sinais e identidade do threadSemaphores and Thread Identity

Os dois tipos de sinais não impõem a identidade do thread em chamadas para os métodos WaitOne, Wait, Release e SemaphoreSlim.Release.The two semaphore types do not enforce thread identity on calls to the WaitOne, Wait, Release, and SemaphoreSlim.Release methods. Por exemplo, um cenário de uso comum para sinais envolve um thread de produtor e um thread de consumidor, com um thread sempre incrementando a contagem de sinais e o outro sempre diminuindo-a.For example, a common usage scenario for semaphores involves a producer thread and a consumer thread, with one thread always incrementing the semaphore count and the other always decrementing it.

É responsabilidade do programador garantir que um thread não libere o sinal muitas vezes.It is the programmer's responsibility to ensure that a thread does not release the semaphore too many times. Por exemplo, suponha que um sinal tenha uma contagem máxima de dois, e que o thread A e o thread B insiram o sinal.For example, suppose a semaphore has a maximum count of two, and that thread A and thread B both enter the semaphore. Se um erro de programação no thread B fizer com que ele chame Release duas vezes, ambas as chamadas serão bem-sucedidas.If a programming error in thread B causes it to call Release twice, both calls succeed. A contagem no sinal está completa e quando o thread A eventualmente chama Release, uma SemaphoreFullException é lançada.The count on the semaphore is full, and when thread A eventually calls Release, a SemaphoreFullException is thrown.

Sinais com nomeNamed Semaphores

O sistema operacional Windows permite que os sinais tenham nomes.The Windows operating system allows semaphores to have names. Um sinal com nome é para todo o sistema.A named semaphore is system wide. Ou seja, depois que o sinal com nome for criado, ele ficará visível para todos os threads em todos os processos.That is, once the named semaphore is created, it is visible to all threads in all processes. Assim, o sinal com nome pode ser usado para sincronizar as atividades de processos, bem como os threads.Thus, named semaphore can be used to synchronize the activities of processes as well as threads.

Você pode criar um objeto Semaphore que representa um sinal de sistema com nome usando um dos construtores que especifica um nome.You can create a Semaphore object that represents a named system semaphore by using one of the constructors that specifies a name.

Observação

Como os sinais com nome são para todo o sistema, é possível ter vários objetos Semaphore que representam o mesmo sinal com nome.Because named semaphores are system wide, it is possible to have multiple Semaphore objects that represent the same named semaphore. Cada vez que você chamar um construtor ou o método Semaphore.OpenExisting, um novo objeto Semaphore é criado.Each time you call a constructor or the Semaphore.OpenExisting method, a new Semaphore object is created. Especificar o mesmo nome repetidas vezes cria vários objetos que representam o mesmo sinal com nome.Specifying the same name repeatedly creates multiple objects that represent the same named semaphore.

Tenha cuidado ao usar sinais com nome.Be careful when you use named semaphores. Como eles são para todo o sistema, outro processo que usa o mesmo nome pode inserir seu sinal inesperadamente.Because they are system wide, another process that uses the same name can enter your semaphore unexpectedly. Código mal-intencionado em execução no mesmo computador pode usar isso como base de um ataque de negação de serviço.Malicious code executing on the same computer could use this as the basis of a denial-of-service attack.

Use a segurança de controle de acesso para proteger um objeto Semaphore que representa um sinal com nome, preferencialmente usando um construtor que especifica um objeto System.Security.AccessControl.SemaphoreSecurity.Use access control security to protect a Semaphore object that represents a named semaphore, preferably by using a constructor that specifies a System.Security.AccessControl.SemaphoreSecurity object. Também é possível aplicar a segurança de controle de acesso usando o método Semaphore.SetAccessControl, mas isso deixa uma janela de vulnerabilidade entre o momento em que o sinal é criado e o momento em que ele é protegido.You can also apply access control security using the Semaphore.SetAccessControl method, but this leaves a window of vulnerability between the time the semaphore is created and the time it is protected. Proteger sinais com a segurança de controle de acesso ajuda a impedir ataques mal-intencionados, mas não resolve o problema de colisão de nome não intencional.Protecting semaphores with access control security helps prevent malicious attacks, but does not solve the problem of unintentional name collisions.

Confira tambémSee also