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.
O .NET fornece um intervalo de tipos que você pode usar para sincronizar o acesso a um recurso compartilhado ou coordenar a interação de thread.
Importante
Use a mesma instância primitiva de sincronização para proteger o acesso de um recurso compartilhado. Se você usar instâncias primitivas de sincronização diferentes para proteger o mesmo recurso, contornará a proteção fornecida por um primitivo de sincronização.
Classe WaitHandle e tipos de sincronização leve
Vários primitivos de sincronização do .NET derivam da System.Threading.WaitHandle classe, que encapsula um identificador de sincronização do sistema operacional nativo e usa um mecanismo de sinalização para interação de thread. Essas classes incluem:
- System.Threading.Mutex, que concede acesso exclusivo a um recurso compartilhado. O estado de um mutex será sinalizado se nenhum thread for seu proprietário.
- System.Threading.Semaphore, que limita o número de threads que podem acessar um recurso compartilhado ou um pool de recursos simultaneamente. O estado de um semáforo é definido como sinalizado quando sua contagem é maior que zero e não atribuída quando sua contagem é zero.
- System.Threading.EventWaitHandle, que representa um evento de sincronização de thread e pode estar em um estado sinalizado ou sem sinal.
- System.Threading.AutoResetEvent, que é derivado de EventWaitHandle e, quando sinalizado, é redefinido automaticamente para um estado não sinalizado após o lançamento de um único thread em espera.
- System.Threading.ManualResetEvent, que deriva de EventWaitHandle e, quando sinalizado, permanece em um estado sinalizado até que o Reset método seja chamado.
No .NET Framework, como WaitHandle deriva de System.MarshalByRefObject, esses tipos podem ser usados para sincronizar as atividades de threads entre os limites de domínio do aplicativo.
No .NET Framework, no .NET Core e no .NET 5+, alguns desses tipos podem representar identificadores de sincronização de sistema nomeados, que são visíveis em todo o sistema operacional e podem ser usados para a sincronização entre processos:
- Mutex
- Semaphore (no Windows)
- EventWaitHandle (no Windows)
Para obter mais informações, consulte a referência de WaitHandle API.
Tipos de sincronização leve não dependem de identificadores do sistema operacional subjacente e normalmente fornecem um melhor desempenho. No entanto, eles não podem ser usados para a sincronização entre processos. Use esses tipos para sincronização de thread em um aplicativo.
Alguns desses tipos são alternativas aos tipos derivados de WaitHandle. Por exemplo, SemaphoreSlim é uma alternativa leve a Semaphore.
Sincronização do acesso a um recurso compartilhado
O .NET fornece um intervalo de primitivos de sincronização para controlar o acesso a um recurso compartilhado por vários threads.
Classe Monitor
A System.Threading.Monitor classe concede acesso mutuamente exclusivo a um recurso compartilhado adquirindo ou liberando um bloqueio no objeto que identifica o recurso. Enquanto um bloqueio é mantido, o thread que mantém o bloqueio pode adquirir e liberar o bloqueio novamente. Qualquer outro thread é impedido de adquirir o bloqueio e o método Monitor.Enter aguardará até que o bloqueio seja liberado. O método Enter adquire um bloqueio liberado. Você também pode usar o método Monitor.TryEnter para especificar o tempo durante o qual um thread tenta adquirir um bloqueio. Porque a classe Monitor tem afinidade de thread, o thread que adquiriu um bloqueio deve liberar o bloqueio chamando o método Monitor.Exit.
Você pode coordenar a interação de threads que adquirem um bloqueio no mesmo objeto usando os métodos Monitor.Wait, Monitor.Pulse e Monitor.PulseAll.
Para obter mais informações, consulte a referência de Monitor API.
Observação
Use a instrução lock em C# e a instrução SyncLock no Visual Basic para sincronizar o acesso a um recurso compartilhado em vez de usar a Monitor classe diretamente. Essas instruções são implementadas usando os métodos Enter e Exit, e um bloco try…finally para garantir que o bloqueio adquirido seja sempre liberado.
Classe Mutex
A System.Threading.Mutex classe, como Monitor, concede acesso exclusivo a um recurso compartilhado. Use uma das sobrecargas do método Mutex.WaitOne para solicitar a propriedade de um mutex. Como Monitor, Mutex tem afinidade de thread e o thread que adquiriu um mutex deverá liberá-lo chamando o método Mutex.ReleaseMutex.
Diferentemente do Monitor, a classe Mutex pode ser usada para sincronização entre processos. Para fazer isso, use um mutex nomeado, que fica visível em todo o sistema operacional. Para criar uma instância de mutex nomeada, use um construtor Mutex que especifica um nome. Você também pode chamar o método Mutex.OpenExisting para abrir um mutex do sistema nomeado existente.
Para obter mais informações, consulte o artigo do Mutexes e a referência à Mutex API.
Estrutura SpinLock
A System.Threading.SpinLock estrutura, como Monitor, concede acesso exclusivo a um recurso compartilhado com base na disponibilidade de um bloqueio. Quando SpinLock tenta adquirir um bloqueio que não está disponível, ele aguarda em um loop, verificando repetidamente até o bloqueio ficar disponível.
Para obter mais informações sobre os benefícios e desvantagens de usar o bloqueio de rotação, consulte o artigo SpinLock e a referência da API SpinLock.
Classe ReaderWriterLockSlim
A System.Threading.ReaderWriterLockSlim classe concede acesso exclusivo a um recurso compartilhado para gravação e permite que vários threads acessem o recurso simultaneamente para leitura. Talvez você queira usar ReaderWriterLockSlim para sincronizar o acesso a uma estrutura de dados compartilhada que dá suporte a operações de leitura thread-safe, mas requer acesso exclusivo para executar a operação de gravação. Quando um thread solicita acesso exclusivo (por exemplo, ao chamar o método ReaderWriterLockSlim.EnterWriteLock), o leitor subsequente solicita o bloqueio até que todos os leitores e gravadores existentes tenham saído do bloqueio e o gravador tenha entrado e saído do bloqueio.
Para obter mais informações, consulte a referência de ReaderWriterLockSlim API.
Classes Semaphore e SemaphoreSlim
As System.Threading.Semaphore e System.Threading.SemaphoreSlim classes limitam o número de threads que podem acessar um recurso compartilhado ou um pool de recursos concomitantemente. Threads adicionais que solicitam o recurso aguardam até que qualquer thread liberar o semáforo. Como o semáforo não tem afinidade de thread, um thread pode adquirir o semáforo e outro pode liberá-lo.
SemaphoreSlim é uma alternativa leve ao Semaphore e pode ser usada apenas para sincronização dentro de um único contexto de processo.
No Windows, você pode usar Semaphore para a sincronização entre processos. Para fazer isso, crie uma Semaphore instância que represente um semáforo do sistema nomeado usando um dos Construtores de Semaphore que especifica um nome ou o Semaphore.OpenExisting método. SemaphoreSlim não oferece suporte a sinais de sistema nomeado.
Para obter mais informações, consulte o artigo Semaphore e SemaphoreSlim e a referência da API de Semaphore ou SemaphoreSlim.
Interação ou sinalização de thread
Interação de thread (ou sinalização do thread) significa que um thread deve aguardar notificação ou um sinal de um ou mais threads para continuar. Por exemplo, se a thread A chamar o método Thread.Join da thread B, a thread A será bloqueada até que a thread B seja concluída. Os primitivos de sincronização descritos na seção anterior fornecem um mecanismo diferente para sinalização: ao liberar um bloqueio, um thread notifica outro thread de que ele pode continuar adquirindo o bloqueio.
Esta seção descreve construções de sinalização adicionais fornecidas pelo .NET.
Classes EventWaitHandle, AutoResetEvent, ManualResetEvent e ManualResetEventSlim
A System.Threading.EventWaitHandle classe representa um evento de sincronização de thread.
Um evento de sincronização pode estar em um estado sem sinal ou sinalizado. Quando o estado de um evento não é sinalizado, um thread que chama a sobrecarga WaitOne do evento é bloqueado até que um evento seja sinalizado. O EventWaitHandle.Set método define o estado de um evento como sinalizado.
O comportamento de um EventWaitHandle que foi assinalado depende de seu modo de redefinição:
- Um EventWaitHandle criado com o sinalizador EventResetMode.AutoReset é redefinido automaticamente após liberar um único thread em espera. É como uma roleta que permite que apenas um thread de cada vez seja sinalizado. A System.Threading.AutoResetEvent classe, da qual deriva EventWaitHandle, representa esse comportamento.
- Um EventWaitHandle criado com a EventResetMode.ManualReset flag continua sinalizado até que o método Reset seja chamado. É como um portão que está fechado até que seja sinalizado e depois fica aberto até alguém fechá-lo. A System.Threading.ManualResetEvent classe, da qual deriva EventWaitHandle, representa esse comportamento. A System.Threading.ManualResetEventSlim classe é uma alternativa leve para ManualResetEvent.
No Windows, você pode usar EventWaitHandle para a sincronização entre processos. Para fazer isso, crie uma EventWaitHandle instância que represente um evento de sincronização de sistema nomeado usando um dos construtores EventWaitHandle que especifica um nome ou o EventWaitHandle.OpenExisting método.
Para obter mais informações, consulte o artigo EventWaitHandle . Para a referência da API, consulte EventWaitHandle, AutoResetEvente ManualResetEventManualResetEventSlim.
Classe CountdownEvent
A System.Threading.CountdownEvent classe representa um evento que se torna definido quando sua contagem é zero. Embora CountdownEvent.CurrentCount seja maior que zero, um thread que chama CountdownEvent.Wait é bloqueado. Chame CountdownEvent.Signal para diminuir a contagem de um evento.
Ao contrário de ManualResetEvent ou ManualResetEventSlim, que você pode usar para desbloquear vários segmentos com um sinal de um único segmento, você pode usar CountdownEvent para desbloquear um ou mais segmentos com sinais de vários segmentos.
Para obter mais informações, consulte o artigo CountdownEvent e a referência à CountdownEvent API.
Classe de barreira
A System.Threading.Barrier classe representa uma barreira de execução de thread. Um thread que chama o Barrier.SignalAndWait método sinaliza que ele atingiu a barreira e aguarda até que outros threads participantes atinjam a barreira. Quando todos os threads participantes atingem a barreira, eles prosseguem e a barreira é redefinida e pode ser usada novamente.
Você pode usar Barrier quando um ou mais threads exigem os resultados de outros threads antes de prosseguir para a próxima fase de computação.
Para obter mais informações, consulte o artigo Barreira e a referência à Barrier API.
Classe Interlocked
A System.Threading.Interlocked classe fornece métodos estáticos que executam operações atômicas simples em uma variável. Essas operações atômicas incluem adição, incremento e decremento, troca e troca condicional que depende de uma comparação e operação de leitura de um valor inteiro de 64 bits.
Para obter mais informações, consulte a referência de Interlocked API.
Estrutura SpinWait
A estrutura System.Threading.SpinWait oferece suporte para espera baseada em rotação. Você pode usá-la quando um thread tiver de esperar pela sinalização de um evento ou por uma condição específica. No entanto, quando o tempo de espera real for menor do que o tempo necessário, use um identificador de espera ou bloqueie o thread. Usando o SpinWait, você pode especificar um curto período de tempo para girar enquanto espera e, em seguida, gerar (por exemplo, aguardando ou em espera) somente se a condição não for atendida no tempo especificado.
Para obter mais informações, consulte o artigo SpinWait e a referência de SpinWait API.