Partilhar via


Sincronizando dados para multithreading

Quando vários threads podem fazer chamadas para as propriedades e métodos de um único objeto, é fundamental que essas chamadas sejam sincronizadas. Caso contrário, um thread pode interromper o que outro thread está fazendo, e o objeto pode ser deixado em um estado inválido. Uma classe cujos membros estão protegidos contra tais interrupções é chamada thread-safe.

O .NET fornece várias estratégias para sincronizar o acesso à instância e aos membros estáticos:

  • Regiões de código sincronizadas. Você pode usar o suporte de Monitor classe ou compilador para essa classe para sincronizar apenas o bloco de código que precisa dele, melhorando o desempenho.

  • Sincronização manual. Você pode usar os objetos de sincronização fornecidos pela biblioteca de classes .NET. Consulte Visão geral das primitivas de sincronização, que inclui uma discussão sobre a Monitor classe.

  • Contextos sincronizados. Somente para aplicativos .NET Framework e Xamarin, você pode usar o para habilitar a SynchronizationAttribute sincronização simples e automática para ContextBoundObject objetos.

  • Classes de System.Collections.Concurrent coleção no namespace. Essas classes fornecem operações de adição e remoção sincronizadas internas. Para obter mais informações, consulte Coleções Thread-Safe.

O common language runtime fornece um modelo de thread no qual as classes se enquadram em várias categorias que podem ser sincronizadas de várias maneiras diferentes, dependendo dos requisitos. A tabela a seguir mostra qual suporte de sincronização é fornecido para campos e métodos com uma determinada categoria de sincronização.

Categoria Campos globais Campos estáticos Métodos estáticos Campos de instância Métodos de instância Blocos de código específicos
Sem sincronização No No No No No Não
Contexto sincronizado No No No Sim Sim No
Regiões de código sincronizadas No Não Apenas se estiver marcado Não Apenas se estiver marcado Apenas se estiver marcado
Sincronização manual Manual Manual Manual Manual Manual Manual

Sem sincronização

Este é o padrão para objetos. Qualquer thread pode acessar qualquer método ou campo a qualquer momento. Apenas um thread de cada vez deve acessar esses objetos.

Sincronização manual

A biblioteca de classes .NET fornece várias classes para sincronizar threads. Consulte Visão geral das primitivas de sincronização.

Regiões de código sincronizadas

Você pode usar a Monitor classe ou uma palavra-chave do compilador para sincronizar blocos de código, métodos de instância e métodos estáticos. Não há suporte para campos estáticos sincronizados.

Visual Basic e C# suportam a marcação de blocos de código com uma palavra-chave de linguagem específica, a lock instrução em C# ou a SyncLock instrução em Visual Basic. Quando o código é executado por um thread, é feita uma tentativa de adquirir o bloqueio. Se o bloqueio já tiver sido adquirido por outro thread, o thread será bloqueado até que o bloqueio fique disponível. Quando o thread sai do bloco sincronizado de código, o bloqueio é liberado, não importa como o thread saia do bloco.

Nota

A partir do C# 13, a lock instrução reconhece se o objeto bloqueado é uma instância de System.Threading.Lock e usa o EnterScope método para criar uma região sincronizada. O lock, quando o destino não é uma Lock instância e SyncLock as instruções são implementadas usando Monitor.Enter e Monitor.Exit, para que outros métodos de Monitor possam ser usados em conjunto com eles dentro da região sincronizada.

Você também pode decorar um método com um MethodImplAttribute valor de MethodImplOptions.Synchronized, que tem o mesmo efeito que usar Monitor ou uma das palavras-chave do compilador para bloquear todo o corpo do método.

Thread.Interrupt pode ser usado para quebrar um thread de operações de bloqueio, como aguardar o acesso a uma região sincronizada de código. Thread.Interrupt também é usado para quebrar threads de operações como Thread.Sleep.

Importante

Não bloqueie o tipo — ou seja, typeof(MyType) em C#, GetType(MyType) no Visual Basic ou MyType::typeid em C++ — para proteger static métodos (Shared métodos em Visual Basic). Em vez disso, use um objeto estático privado. Da mesma forma, não use this em C# (Me no Visual Basic) para bloquear métodos de instância. Em vez disso, use um objeto particular. Uma classe ou instância pode ser bloqueada por código diferente do seu, potencialmente causando deadlocks ou problemas de desempenho.

Suporte a compiladores

Visual Basic e C# oferecem suporte a uma palavra-chave de linguagem que usa Monitor.Enter e Monitor.Exit para bloquear o objeto. Visual Basic suporta a instrução SyncLock ; C# suporta a instrução lock .

Em ambos os casos, se uma exceção for lançada no bloco de código, o bloqueio adquirido pelo bloqueio ou SyncLock será liberado automaticamente. Os compiladores C# e Visual Basic emitem um bloco try/finally com Monitor.Enter no início da tentativa e Monitor.Exit no bloco final. Se uma exceção for lançada dentro do bloqueio ou bloco SyncLock, o manipulador final será executado para permitir que você faça qualquer trabalho de limpeza.

Contexto sincronizado

Somente em aplicativos .NET Framework e Xamarin, você pode usar o SynchronizationAttribute em qualquer ContextBoundObject para sincronizar todos os métodos e campos de instância. Todos os objetos no mesmo domínio de contexto compartilham o mesmo bloqueio. Vários threads têm permissão para acessar os métodos e campos, mas apenas um único thread é permitido a qualquer momento.

Consulte também