Técnicas de Sincronização Avançada

Aplicativos multissegmentados frequentemente usam alças e objetos monitores para sincronizar vários segmentos.Estas seções explicam como usar o seguinte .NET Framework classes ao sincronizar segmentos: AutoResetEvent, Interlocked, ManualResetEvent, Monitor, Mutex, ReaderWriterLock, Timer, WaitHandle.

Identificadores de Espera

Identificadores de espera são objetos que sinalizam o status de um segmento para outro segmento.Segmentos podem usar identificadores de espera para notificar outros segmentos que precisem de acesso exclusivo a um recurso.Então outros segmentos devem esperar para usar este recurso até que o identificador de espera não esteja mais em uso.Identificadores de espera têm dois estados, signaled e nonsignaled.Um identificador de espera que não é propriedade de qualquer segmento está no estado signaled.Um identificador de espera que pertence a um segmento está no estado nonsignaled.

Threads solicitam a propriedade de um identificador de espera chamando um dos métodos de espera, tais como WaitOne, WaitAny, ou WaitAll.Os métodos de espera são chamadas bloqueadoras que são semelhantes ao método Join de um thread individual:

  • Se nenhum outro thread possui o identificador de espera, a chamada retorna True imediatamente, o identificador de espera do status é alterado para não sinalizado e o thread que possui o identificador de espera continuará a ser executado.

  • Se um segmento chama um dos métodos de espera do identificador de espera, mas o identificador de espera é pertencente a outro segmento, o segmento de chamada esperará por um período especificado (se um tempo limite é especificado) ou esperará indefinidamente (se nenhum tempo limite for especificado) para o outro segmento para liberar o identificador de espera.Se um tempo limite é especificado e o identificador de espera for liberado antes do tempo limite expirar, a chamada retorna True.Caso contrário, a chamada para espera retorna False e o thread de chamada continuará a ser executado.

Threads que possuem um identificador de espera chamam o método Set quando eles terminam ou quando eles não precisam mais do identificador de espera.Outros s thread pode reiniciar o status de um identificador de espera para nonsignaled chamando o Reset método ou chamando WaitOne, WaitAny, ou WaitAll e com êxito esperando por um thread chamar Set. AutoResetEvent alças são redefinidas automaticamente para nonsignaled pelo sistema após um segmento único de espera ter sido liberado. Se nenhum segmento estiver aguardando, o estado do objeto evento permanece signaled.

Há três tipos de identificadores de espera comumente usados com Visual Basic: objetos mutex, ManualResetEvent, e AutoResetEvent. Os dois últimos são geralmente denominados eventos de sincronização.

Objetos mutex

Objetos mutex são objetos de sincronização que podem ser possuídos por somente um único segmento ao mesmo tempo.O nome " mutex " é derivado do fato de que a propriedade de objetos mutex é mutuamente exclusiva.Segmentos solicitam a propriedade do objeto mutex quando eles exigem acesso exclusivo a um recurso.Porque apenas um segmento pode possuir um objeto mutex a qualquer momento, outros segmentos devem aguardar para a propriedade de um objeto mutex antes de usar o recurso.

O método WaitOne resulta em um thread de chamada para aguardar a propriedade de um objeto Mutex.Se um segmento termina normalmente enquanto possue um objeto mutex, o estado do objeto mutex é definido signaled e o seguinte segmento em espera obtém a posse.

Eventos de Sincronização

Eventos de sincronização notificam outros segmentos que algo ocorreu ou que um recurso está disponível.Apesar do termo incluir a palavra " evento ", eventos de sincronização são diferente de outros eventos do Visual Basic — eles são realmente identificadores de espera.Como outros identificadores de espera, eventos sincronização têm dois estados, signaled e nonsignaled.

Segmentos que chamam um dos métodos de espera de um evento de sincronização devem aguardar até que os outras threads sinalizem o evento, chamando o método Set.Há duas classes de evento de sincronização: ManualResetEvent e AutoResetEvent.

Threads definem o status das instâncias ManualResetEvent para sinalizar usando o método Set.Threads definem o status das instâncias ManualResetEvent para não sinalizados usando o método Reset ou quando o controle retorna para uma chamada de WaitOne esperando.

Instâncias da classe AutoResetEvent também podem ser definidas como sinalizadas usando Set, mas elas retornarão automaticamente para nonsignaled tão logo um thread em espera for notificado que o evento tornou-se sinalizado.

Objetos Monitor e SyncLock

Objetos Monitor são usados para garantir que um bloco de código seja executado sem ser interrompido por código em execução em outros segmentos.Em outras palavras, código em outros segmentos não podem executar até que tenha sido terminada a execução do código no bloco sincronizado.

Suponha que, por exemplo, você tenha um programa que repetidamente e de forma assíncrona leia dados e exiba os resultados.Com sistemas operacionais que usam multitarefa com escala de precedência, um segmento em execução pode ser interrompido pelo sistema operacional para permitir um tempo para algum outro segmento executar.Sem sincronização, é possível que você possa obter um exibição parcialmente atualizada dos dados se o objeto que representa os dados for modificada por outro segmento enquanto o dado está sendo exibido.Objetos monitor garantem que uma seção de código será executado sem interrupção.Visual Basic Fornece o SyncLock e End SyncLock instruções para simplificar o acesso aos objetos monitor. Visual C# usa o Lock palavra-chave da mesma maneira.

Observação:

Acesso a um objeto está bloqueado somente se o código de acesso estiver contido dentro de um SyncLock Bloquear na mesma instância do objeto.

Para obter informações sobre a instrução SyncLock, consulte SyncLock Statement

Classe Interlocked

Você pode usar os métodos da classe Interlocked para evitar problemas que podem ocorrer quando vários segmentos tentarem simultaneamente atualizar ou comparar o mesmo valor.Os métodos dessa classe permitem o incremento, diminuição, troca e comparação de valores de qualquer segmento seguro.O exemplo a seguir mostra como usar o método Increment para incrementa uma variável que é compartilhada por procedimentos em execução em segmentos separados.

Sub ThreadA(ByRef IntA As Integer)
    System.Threading.Interlocked.Increment(IntA)
End Sub

Sub ThreadB(ByRef IntA As Integer)
    System.Threading.Interlocked.Increment(IntA)
End Sub

Bloqueios ReaderWriter

Em alguns casos, você pode querer bloquear um recurso somente quando os dados estiverem sendo escritos e permitir que vários clientes simultaneamente leiam os dados quando estes não estiverem sendo atualizados.A classe ReaderWriterLock garante o acesso exclusivo a um recurso enquanto um segmento está modificando o recurso, mas ele permite acesso não exclusivo ao ler o recurso.Bloqueios ReaderWriter são uma alternativa útil para bloqueios exclusivos que causam outros segmentos para esperar, mesmo quando os segmentos não precisam atualizar dados.

Deadlocks

Sincronização de segmentos são incalculáveis em aplicativos multissegmentados, mas há sempre o perigo de criar um deadlock, onde vários segmentos estão aguardando um pelo outro e o aplicativo chega a uma interrupção.Um deadlock é análogo a uma situação na qual carros são estacionados em uma parada de quatro vias e cada pessoa está aguardando a outra para ir.Evitar deadlocks é importante; a chave é um planejamento cuidadoso.Geralmente você pode prever situações de bloqueio por diagramação de aplicativos multissegmentados antes de iniciar a codificação.

Consulte também

Conceitos

Multithreading Avançado com Visual Basic

Sincronização de Segmento

Estados de Thread

Aplicativos Multithreaded

Referência

System.Threading

Instrução SyncLock

Outros recursos

Multithreading in Components