Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A System.Threading.Semaphore classe representa um semáforo nomeado (sistêmico) ou local. É uma camada fina que envolve o objeto de semáforo Win32. Semáforos Win32 são semáforos contadores, que podem ser usados para controlar o acesso a um pool de recursos.
A SemaphoreSlim classe representa um semáforo leve e rápido que pode ser usado para aguardar em um único processo quando os tempos de espera devem ser muito curtos. SemaphoreSlim depende o máximo possível dos primitivos de sincronização fornecidos pelo CLR (Common Language Runtime). No entanto, fornece também identificadores de espera baseados no kernel inicializados lentamente, conforme necessário para dar suporte à espera de vários sinais. 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.
Gerenciando um recurso limitado
As threads entram no semáforo chamando o método WaitOne, que é herdado da classe WaitHandle, no caso de um objeto System.Threading.Semaphore ou do método SemaphoreSlim.WaitSemaphoreSlim.WaitAsync, no caso de um objeto SemaphoreSlim. Quando a chamada é retornada, a contagem no sinal é reduzida. Quando um thread solicita entrada e a contagem é zero, o thread bloqueia. À 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. 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.
Um thread pode inserir o sinal várias vezes chamando do objeto System.Threading.Semaphore o método WaitOne ou do objeto SemaphoreSlim o método Wait repetidas vezes. 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.
Sinais e identidade do thread
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. 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.
É responsabilidade do programador garantir que um thread não libere o semáforo muitas vezes. 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. Se um erro de programação no thread B fizer com que ele chame Release
duas vezes, ambas as chamadas são bem-sucedidas. A contagem no sinal está completa e quando o thread A eventualmente chama Release
, uma SemaphoreFullException é lançada.
Sinais com nome
O sistema operacional Windows permite que os semáforos tenham nomes. Um sinal com nome é para todo o sistema. Ou seja, depois que o sinal com nome for criado, ele ficará visível para todos os threads em todos os processos. Assim, o sinal com nome pode ser usado para sincronizar as atividades de processos, bem como os threads.
Você pode criar um Semaphore objeto que representa um semáforo do sistema nomeado usando um dos construtores que especifica um nome.
Observação
Como os semáforos nomeados abrangem todo o sistema, é possível ter vários Semaphore objetos que representam o mesmo semáforo nomeado. Sempre que você chama um construtor ou o Semaphore.OpenExisting método, um novo Semaphore objeto é criado. Especificar o mesmo nome cria repetidamente vários objetos que representam o mesmo semáforo nomeado.
Tenha cuidado ao usar semáforos nomeados. Como elas abrangem todo o sistema, outro processo que usa o mesmo nome pode invadir seu semáforo inesperadamente. A execução de código mal-intencionado no mesmo computador pode usar isso como base de um ataque de negação de serviço.
Use a segurança do controle de acesso para proteger um Semaphore objeto que representa um semáforo nomeado, preferencialmente usando um construtor que especifica um System.Security.AccessControl.SemaphoreSecurity objeto. Você também pode aplicar a segurança do controle de acesso usando o Semaphore.SetAccessControl método, mas isso deixa uma janela de vulnerabilidade entre o momento em que o semáforo é criado e a hora em que ele é protegido. 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.