Pergunta

Digamos que eu tenha uma estrutura que consiste em 100 bytes.Que garantias tenho sobre o código a seguir?

m_myLargeStruct = someValue; // copying 100 bytes
Thread.MemoryBarrier();

// Executed by another thread, after "Thread.MemoryBarrier" was called by the first thread
Console.WriteLine(m_myLargeStruct.ToString());

O modelo de memória garante que a cópia de 100 bytes estará completa após a colocação da barreira de memória?ou as barreiras de memória se aplicam apenas a tipos do tamanho da arquitetura do processador?(4 bytes para 32 bits e 8 bytes para 64 bits).
Será esta a razão pela qual volátil palavra-chave se aplica apenas a tipos primitivos?(se eu declarar um membro de 8 bytes como volátil, isso significa que uma instrução interligada será usada para alterar seu valor?[já que a atomicidade não é garantida para tipos maiores que 4 bytes em máquinas de 32 bits]).

Espero ter sido claro o suficiente..:)
Obrigado

Foi útil?

Solução

Claramente a resposta é não, ou melhor, você não tem garantias sobre nada. Nada impede que o sistema operacional trocasse o thread que está escrevendo para a estrutura de 100 bytes antes de iniciar o thread que imprime a estrutura de 100 bytes.

Uma barreira de memória é usada quando você deseja coordenar o acesso aos dados por meio de um sinalizador ou algum outro valor atômico. Não sei o que exatamente você está tentando fazer, então não posso lhe dar um bom código de exemplo sobre como você deve fazer isso.

Outras dicas

A menos que o tópico de leitura tenha uma barreira de memória também, eu não acho Isso vai te ajudar muito.

Pessoalmente, eu me esquivaria de:

  • Estruturas que são tão grandes
  • Criar profundamente no modelo de memória para escrever código sem bloqueio

... A menos que você tenha um motivo realmente importante para fazê -lo. Isso é imensamente difícil de obter codificação sem bloqueio com dados mutáveis; Eu acredito que mesmo os especialistas lutam. Normalmente, acho que a abordagem "Tire um bloqueio para cada bloco que acesse os dados" é mais fácil de acertar e é bom em termos de desempenho para 99% dos casos.

Confio na equipe PFX da Microsoft para acertar a codificação sem bloqueio e, para que eles me forneçam com maneiras pelas quais posso usar o código deles para escrever meus próprios programas de bloqueio com relativa facilidade. Não confio em mim mesmo para acertar esse tipo de coisa. Se eu precisar usar explicitamente uma barreira de memória, isso provavelmente significa que estou me esforçando demais.

Você precisa de outra barreira de memória no segundo tópico, antes do Writeline. (Se o seu sistema fornecer barreiras assimétricas de memória, é suficiente para executar uma barreira de liberação após a atribuição e uma barreira de aquisição antes do Writeline).

O tamanho dos dados não importa.

Você precisa de uma barreira de memória nos dois lugares/threads e, é claro, precisa de algum tipo de sincronização entre os dois, para que a barreira do Thread do 2º não fique 'executada' antes do primeiro thread.

Especificamente, o tópico de escrita precisa de uma barreira de memória 'liberação', e o thread de leitura precisa de uma barreira de memória 'adquirir' (se a plataforma subjacente suportar a semântica de barreira separada).

A menos que você esteja pedindo curiosidade acadêmica ou esteja escrevendo sua própria estrutura, você realmente deve usar um objeto de sincronização da biblioteca/estrutura/plataforma. Tentar resolver tudo isso é complicado e já está feito nos objetos de sincronização fornecidos.

Bem, antes de tudo você não deveria ter uma estrutura tão grande.A menos que você seja extremamente cuidadoso ao usar a estrutura, ela será mais lenta do que usar uma classe.Além disso, é contra-intuitivo para a semântica de valor das estruturas.

Dito isto, a barreira de memória garantirá que a estrutura seja copiada.A otimização não moverá nenhuma instrução através da barreira.

A palavra-chave volátil é um pouco diferente.Garante que nenhuma operação contra a variável seja otimizada e garante a ordem dos acessos à memória.No entanto, para tipos de dados que não podem ser acessados ​​atomicamente, é praticamente inútil para fins de threading, pois você ainda pode ler metade de um valor novo e metade de um valor antigo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top