Visão geral dos primitivos de sincronização
A.NET Framework fornece uma variedade de primitivos de sincronização para controlar as interações de segmentos e evitar condições de corrida. Eles podem ser divididos em três categorias: operações interligadas, sinalização e bloqueio.
As categorias não são organizados nem claramente definidos: Alguns mecanismos de sincronização têm características de várias categorias; eventos de lançamento de um único thread por vez são funcionalmente como bloqueios; o lançamento de qualquer bloqueio pode ser considerado como um sinal; e operações interligadas podem ser usadas para construir os bloqueios. No entanto, as categorias ainda são úteis.
É importante lembrar que a sincronização de threads é cooperativa. Se um mesmo segmento ignora o mecanismo de sincronização e acessa diretamente o recurso protegido, esse mecanismo de sincronização não pode ser eficaz.
Esta visão geral contém as seções a seguir:
O bloqueio
Sinalização
Tipos de sincronização leve
SpinWait
Operações interligadas
O bloqueio
Bloqueios dar o controle de um recurso para um segmento por vez, ou para um determinado número de threads. Um segmento que solicita um bloqueio exclusivo quando o bloqueio está em uso bloqueia até que o bloqueio se torna disponível.
Bloqueios exclusivos
A forma mais simples de bloqueio é C# lock instrução (SyncLock em Visual Basic), que controla o acesso a um bloco de código. Como um bloco é citado freqüentemente como uma seção crítica. O lock instrução é implementada usando o Enter e Exit métodos para a Monitor classe e usa try…catch…finally para garantir que o bloqueio será liberado.
Em geral, usando o lock a instrução para proteger os pequenos blocos de código, nunca abrangendo mais de um único método, é a melhor maneira de usar o Monitor classe. Embora poderoso, o Monitor classe está sujeita a bloqueios órfãos e deadlocks.
Classe Monitor
O Monitor classe fornece funcionalidade adicional, que pode ser usada em conjunto com o lock instrução:
O TryEnter método permite que um thread que está bloqueado aguardando para o recurso de desistir após um intervalo especificado. Ele retorna um valor booleano indicando êxito ou falha, o que pode ser usada para detectar e evitar deadlocks potenciais.
O Wait método é chamado por um thread em uma seção crítica. Ele oferece controle do recurso e bloqueia até que o recurso está disponível novamente.
O Pulse e PulseAll métodos permitem que um thread que está prestes a liberar o bloqueio ou chamar Wait para colocar um ou mais threads na fila de pronta para que eles podem adquirir o bloqueio.
Tempos limite na Wait sobrecargas do método permitem aguardando segmentos de escape para a fila de pronto.
O Monitor classe pode fornecer proteção em vários domínios de aplicativo, se o objeto usado para o bloqueio deriva de MarshalByRefObject.
Monitortem afinidade de thread. Ou seja, um thread que inseriu o monitor deve sair chamando Exit ou Wait.
O Monitor classe não pode ser instanciado. Seus métodos são estáticos (Shared em Visual Basic) e agir em um objeto de bloqueio pode ser instanciado.
Para uma visão geral conceitual, consulte Monitores.
Classe Mutex
Solicitação de threads um Mutex chamando uma sobrecarga de sua WaitOne método. Sobrecargas com tempos limite são fornecidas para permitir que os threads desistir da espera. Ao contrário do Monitor classe, um mutex pode ser local ou global. Mutexes globais, também chamados nomeado mutexes, são visíveis em todo o sistema operacional e pode ser usados para sincronizar threads em vários domínios de aplicativos ou processos. Locais mutexes derivam de MarshalByRefObjecte pode ser usado entre limites de domínio de aplicativo.
Além disso, Mutex deriva de WaitHandle, o que significa que pode ser usado com mecanismos de sinalização fornecidos pelo WaitHandle, como o WaitAll, WaitAny, e SignalAndWait métodos.
Como Monitor, Mutex tem afinidade de thread. Ao contrário de Monitor, um Mutex é um objeto pode ser instanciado.
Para uma visão geral conceitual, consulte Exclusões mútuas.
Classe de SpinLock
Começando com o .NET Framework versão 4, você pode usar o SpinLock classe quando a sobrecarga exigida pelo Monitor degrada o desempenho. Quando SpinLock encontra uma seção crítica bloqueada, ele simplesmente gira em um loop até que o bloqueio se torna disponível. Se o bloqueio for mantido por um tempo muito curto, girando pode fornecer um desempenho melhor que o bloqueio. No entanto, se o bloqueio for mantido por mais de algumas dezenas de ciclos, SpinLock executa tão bem como Monitor, mas utilizará mais ciclos de CPU e, portanto, pode degradar o desempenho de outros segmentos ou processos.
Outros bloqueios.
Bloqueios não precisam ser exclusivos. Muitas vezes é útil permitir acesso simultâneo a um recurso de um número limitado de segmentos. Semáforos e bloqueios de leitor-gravador foram projetados para controlar esse tipo de acesso a recursos em pool.
ReaderWriterLock classe
O ReaderWriterLockSlim classe aborda o caso em que um thread que as alterações de dados, o escritor deve ter acesso exclusivo a um recurso. Quando o gravador não está ativo, qualquer número de leitores pode acessar o recurso (por exemplo, chamando o EnterReadLock método). Quando um thread solicita acesso exclusivo, (por exemplo, chamando o EnterWriteLock método), bloco de solicitações subseqüentes do leitor até que todos os leitores existentes tenham saído do bloqueio e o gravador inseriu e saiu de bloqueio.
ReaderWriterLockSlimtem afinidade de thread.
Para uma visão geral conceitual, consulte Bloqueios de leitor-gravador..
Classe Semaphore
O Semaphore classe permite que um determinado número de threads para acessar um recurso. Threads adicionais solicitando o bloco de recurso até que um segmento libera o semaphore.
Como o Mutex classe, Semaphore deriva de WaitHandle. Além disso, como Mutex, um Semaphore pode ser local ou global. Ele pode ser usado nos limites do domínio de aplicativo.
Ao contrário de Monitor, Mutex, e ReaderWriterLock, Semaphore não tem afinidade de thread. Isso significa que ele pode ser usado em cenários onde um segmento adquire o semáforo e o outro a versões.
Para uma visão geral conceitual, consulte Semáforo e SemaphoreSlim.
System.Threading.SemaphoreSlimé um semáforo leve para a sincronização em um limite de um único processo.
Voltar ao topo
Sinalização
A maneira mais simples de aguardar um sinal de outro segmento é chamar o Join método, que bloqueia até que o outro segmento seja concluído. Jointem duas sobrecargas que permitem que o thread bloqueado para interromper a espera após um intervalo especificado tiver decorrido.
Identificadores de espera fornecem um conjunto muito mais rico de esperar e recursos de sinalização.
Identificadores de Espera
Identificadores de espera derivam de WaitHandle classe, que por sua vez é derivada de MarshalByRefObject. Assim, os identificadores de espera podem ser usados para sincronizar as atividades de threads de limites de domínio de aplicativo.
Trata do bloco de threads em espera, chamando o método de instância WaitOne ou um dos métodos estáticos WaitAll, WaitAny, ou SignalAndWait. Como eles são lançados depende de qual método foi chamado e o tipo de identificadores de espera.
Para uma visão geral conceitual, consulte Identificadores de Espera.
Identificadores de espera do evento
Identificadores de espera do evento incluem o EventWaitHandle classe e suas classes derivadas, AutoResetEvent e ManualResetEvent. Segmentos são liberados de um identificador de espera do evento quando o identificador de espera do evento é sinalizado chamando seu Set método ou usando o SignalAndWait método.
Reponha próprios automaticamente, como uma borboleta que permite apenas um thread por meio de cada vez que ele é sinalizado ou deve ser redefinido manualmente, como um portão que está fechado até sinalizado e abra até que alguém o fecha de identificadores de espera do evento. Como seus nomes sugerem, AutoResetEvent e ManualResetEvent representam o primeiro e segundo, respectivamente. System.Threading.ManualResetEventSlimé um evento leve para a sincronização em um limite de um único processo.
Um EventWaitHandle pode representar qualquer tipo de evento e pode ser local ou global. As classes derivadas AutoResetEvent e ManualResetEvent são sempre local.
Identificadores de espera do evento não tem afinidade de thread. Qualquer segmento pode sinalizar um identificador de espera do evento.
Para uma visão geral conceitual, consulte EventWaitHandle, AutoResetEvent, CountdownEvent e ManualResetEvent.
Mutex e Classes de semáforo
Porque o Mutex e Semaphore derivam de WaitHandle, eles podem ser usados com os métodos estáticos de WaitHandle. Por exemplo, um segmento pode usar o WaitAll método aguardar até que todos os três seguintes forem verdadeiras: um EventWaitHandle está sinalizado, uma Mutex é liberado e um Semaphore é liberada. Da mesma forma, um thread pode usar o WaitAny método aguardar até que alguma dessas condições for verdadeira.
Para um Mutex ou um Semaphore, que está sendo sinalizado significa released. Se o tipo é usado como o primeiro argumento da SignalAndWait método, ele é liberado. No caso de um Mutex, que tem afinidade de segmento, uma exceção é lançada se o thread de chamada não possui o mutex. Conforme observado anteriormente, semáforos não têm afinidade de thread.
Barreira
O Barrier classe fornece uma maneira de sincronizar cyclically vários segmentos, para que todos os blocos ao mesmo ponto e esperar que todos os outros threads concluir. Uma barreira é útil quando um ou mais threads exigem os resultados de outro thread antes de prosseguir para a próxima fase de um algoritmo. Para obter mais informações, consulte Barreira (.NET Framework).
Voltar ao topo
Tipos de sincronização leve
Começando com o .NET Framework 4, você pode usar os primitivos de sincronização que fornecem desempenho rápido, evitando a dependência cara de objetos de kernel do Win32, como esperar manipula sempre que possível. Em geral, você deve usar esses tipos de quando os tempos de espera são curtos e somente quando os tipos de sincronização original foi tentados e considerados insatisfatório. Os tipos de leves não podem ser usados em cenários que exigem a comunicação entre processos.
System.Threading.SemaphoreSlimé uma versão leve do System.Threading.Semaphore.
System.Threading.ManualResetEventSlimé uma versão leve do System.Threading.ManualResetEvent.
System.Threading.CountdownEventrepresenta um evento que se torna sinalizado quando a contagem é zero.
System.Threading.Barrierpermite que vários threads sincronizar com outro, sem a necessidade de controle por um thread mestre. Uma barreira impede que cada thread continuar até que todos os threads atingiu um ponto especificado.
Voltar ao topo
SpinWait
Começando com o .NET Framework 4, você pode usar o System.Threading.SpinWait estrutura quando um thread tem de esperar por um evento deve ser sinalizado ou uma condição a ser atendida, mas quando o tempo de espera real deve ser menor do que o tempo de espera necessário usando um identificador de espera ou caso contrário, o bloqueio do thread atual. Usando SpinWait, você pode especificar um curto período de tempo de rotação enquanto aguardam e, em seguida, produzir (por exemplo, por espera ou de repouso) somente se a condição não foi atendida no horário especificado.
Voltar ao topo
Operações interligadas
Operações interligadas são simples operações atômicas, realizadas em um local de memória por métodos estáticos da Interlocked classe. Essas operações atômicas incluem adição, incrementam e decrementam, exchange, o exchange condicional, dependendo de uma comparação e operações para os valores de 64 bits em plataformas de 32 bits de leitura.
Observação
A garantia de atomicidade está limitada a operações individuais; Quando várias operações devem ser executadas como uma unidade, um mecanismo de sincronização mais refinado deve ser usado.
Embora nenhuma dessas operações são bloqueios ou sinais, pode ser usados para construir os sinais e bloqueios. Porque eles são nativos do sistema operacional Windows, as operações interligadas são extremamente rápidas.
Operações interligadas podem ser usadas com garantias de memória volátil para escrever aplicativos que exibem a simultaneidade de poderosa sem bloqueio. No entanto, eles exigem sofisticados, de baixo nível de programação, portanto, para fins de maioria dos bloqueios simples são uma opção melhor.
Para uma visão geral conceitual, consulte Operações interligadas.
Voltar ao topo
Consulte também
Conceitos
Sincronizando dados de Multithreading
Outros recursos
EventWaitHandle, AutoResetEvent, CountdownEvent e ManualResetEvent