C #: e se um método estático for chamado de vários threads?

93

Em meu aplicativo, tenho um método estático que é chamado de vários threads ao mesmo tempo. Existe algum perigo de meus dados serem misturados?

Em minha primeira tentativa, o método não era estático e eu estava criando várias instâncias da classe. Nesse caso, meus dados se confundiram de alguma forma. Não tenho certeza de como isso acontece porque só acontece às vezes. Ainda estou depurando. Mas agora o método está estático em Não tenho problemas até agora. Talvez seja apenas sorte. Não tenho certeza.

TalkingCode
fonte

Respostas:

96

Variáveis ​​declaradas dentro de métodos (com a possível exceção de variáveis ​​" capturadas ") são isoladas, então você não obterá problemas inerentes; entretanto, se o seu método estático acessa qualquer estado compartilhado, todas as apostas estão canceladas.

Exemplos de estado compartilhado seriam:

  • campos estáticos
  • objetos acessados ​​de um cache comum (não serializado)
  • dados obtidos por meio dos parâmetros de entrada (e estado desses objetos), se for possível que vários threads estejam tocando o (s) mesmo (s) objeto (s)

Se você compartilhou o estado, você deve:

  • tome cuidado para não alterar o estado, uma vez que ele pode ser compartilhado (melhor: use objetos imutáveis ​​para representar o estado e tire um instantâneo do estado em uma variável local - ou seja, em vez de fazer referência whatever.SomeDatarepetidamente, você lê whatever.SomeData uma vez em uma variável local, e então apenas use a variável - observe que isso só ajuda em estados imutáveis!)
  • sincronizar o acesso aos dados (todos os threads devem ser sincronizados) - seja mutuamente exclusivo ou (mais granular) leitor / gravador
Marc Gravell
fonte
1
@Diego - esse comentário é dirigido a mim ou a @Holli?
Marc Gravell
Ao Holli, só para acrescentar algumas informações práticas à sua resposta.
Diego Pereyra
1
@Marc Não posso concordar totalmente com "Variáveis ​​declaradas dentro de métodos (com a possível exceção de variáveis" capturadas ") são isoladas". Considere um identificador de arquivo que é declarado em um método estático. Então, um thread pode acessar o identificador quando algum outro thread o estiver usando. Isso levará a um comportamento inesperado. Ou sua variável "capturada" também significa "manipulação de arquivo".
prabhakaran de
9
@prabhakaran se um identificador de arquivo for uma variável de método, ele terá como escopo apenas aquele chamador. Qualquer outro chamador estará falando com uma variável diferente (as variáveis ​​de método são por chamada). Agora, o acesso ao arquivo subjacente é um problema separado, mas não está relacionado a c # ou .NET. Se o identificador não for compartilhado, pode-se esperar algum tipo de mutex / bloqueio se esse cenário for provável.
Marc Gravell
28

Sim, é apenas sorte. ;)

Não importa se o método é estático ou não, o que importa é se os dados são estáticos ou não.

Se cada thread tiver sua própria instância separada da classe com seu próprio conjunto de dados, não há risco de os dados serem misturados. Se os dados forem estáticos, haverá apenas um conjunto de dados e todos os threads compartilham os mesmos dados, portanto, não há como não misturá-los.

Quando seus dados em instâncias separadas ainda se misturam, é mais provável que os dados não estejam realmente separados.

Guffa
fonte
6
Adorei essa linha - It doesn't matter if the method is static or not, what matters is if the data is static or not. Apenas para adicionar, as variáveis ​​locais declaradas dentro do escopo de um método estático não formam aquela parte dos dados com a qual precisamos nos preocupar no cenário dado.
RBT de
Ótima resposta. Ajudou muito.
Fractal de
15

Os métodos estáticos devem ser adequados para vários threads.

Os dados estáticos, por outro lado, podem causar um problema porque as tentativas de acessar os mesmos dados de diferentes threads precisam ser controladas para garantir que apenas um thread por vez esteja lendo ou gravando os dados.

Doug Ferguson
fonte
2
A palavra-chave aqui é sincronização :-)
G. Stoynev
2
a leitura pode acontecer simultaneamente, mas a leitura E a escrita ao mesmo tempo levarão a um comportamento inesperado
Freestyle076
9

MSDN sempre diz:

Qualquer membro público estático (compartilhado no Visual Basic) desse tipo é seguro para threads. Não é garantido que nenhum membro da instância seja thread-safe.

Edit: Como os caras aqui dizem, nem sempre é o caso, e claramente isso se aplica a classes projetadas dessa forma no BCL, não a classes criadas pelo usuário onde isso não se aplica.

Marcote
fonte
3
Ufa! Finalmente, entendi o significado desta nota, que é encontrada com frequência na documentação do MSDN. Então, basicamente, quando a MS projeta um método estático (onde esta nota é publicada) em BCL, eles não acessam nenhuma variável / membro / estado que esteja fora do escopo desse método. Eles dependem completamente de variáveis ​​locais com escopo de método apenas para implementar a lógica desse método. Muito feliz que você compartilhou.
RBT
@Marcote, o oposto não é verdade? Os membros da instância são seguros porque há um por instância. No entanto, os membros estáticos não são seguros para thread porque são compartilhados entre todas as instâncias dessa classe. quora.com/…
Fractal de
1
depende. Eu nunca trataria um membro de instância seguro por padrão. É por isso que todo um conjunto de bibliotecas e para evitar a corrupção de dados entre muitas outras coisas.
Marcote
1
ok, obrigado @Marcote. Aos poucos, estou descobrindo que tenho muito a aprender.
Fractal de