Existe alguma vantagem de usar palavras -chave voláteis em contraste em usar a classe interligada?

StackOverflow https://stackoverflow.com/questions/1701216

Pergunta

Em outras palavras, posso fazer algo com uma variável volátil que também não poderia ser resolvida com uma variável normal e a classe interligada?

Foi útil?

Solução

Editar: Pergunta amplamente reescrita

Para responder a essa pergunta, eu mergulhei um pouco mais longe no assunto e descobri algumas coisas sobre volatile e Interlocked que eu não estava ciente. Vamos esclarecer isso, não apenas para mim, mas para esta discussão e outras pessoas lendo sobre isso:

  • volatile Leia/gravação deve ser imune à reordenação. este significa ler e escrever, faz não significa qualquer outra ação;
  • volatilidade não é forçado na CPU, ou seja, nível de hardware (x86 usa adquirir e liberar cercas em algum ler escrever). Isso evita otimizações de compilador ou CLR;
  • Interlocked usa instruções de montagem atômica para comparexchange (cmpxchg), Incremento (inc) etc;
  • Interlocked usa uma fechadura às vezes: um Bloqueio de hardware em sistemas multi processadores; Nos sistemas Uni-Processor, não há bloqueio de hardware;
  • Interlocked é diferente de volatile naquele que usa um cerca completa, onde o volátil usa meia cerca.
  • Uma leitura após uma gravação pode ser reordenada Quando você usa volatile. Não pode acontecer com Interlocked. VolatileRead e VolatileWrite Tenha o mesmo problema de reordenação que `volátil (link graças a Brian Gideon).

Agora que temos as regras, podemos definir uma resposta para sua pergunta:

  • Tecnicamente: sim, há coisas que você pode fazer com volatile que você não pode fazer Interlocked:
    1. Sintaxe: você não pode escrever a = b Onde a ou b é volátil, mas isso é óbvio;
    2. Você pode ler um valor diferente depois de escrevê -lo em uma variável volátil por causa da reordenação. Você não pode fazer isso com Interlocked. Em outras palavras: você pode ser menos seguro com volatile Então você pode estar com Interlocked.
    3. Atuação: volatile é mais rápido então Interlocked.
  • Semanticamente: não, porque Interlocked Simplesmente fornece um superconjunto de operações e é mais seguro usar porque aplica cercas completas. Você não pode fazer nada com volatile que você não pode fazer Interlocked E você pode fazer muito com Interlocked que você não pode fazer com volátil:

    static volatile int x = 0;
    x++;                        // non-atomic
    static int y = 0;
    Interlocked.Increment(y);   // atomic
    
  • Escopo: sim, declarando uma variável volatile Torna volátil para cada acesso. É impossível forçar esse comportamento de qualquer outra maneira, daí volatile não pode ser substituído por Interlocked. Isso é necessário em cenários em que outras bibliotecas, interfaces ou hardware podem acessar sua variável e atualizá -la a qualquer momento ou precisar da versão mais recente.

Se você me perguntar, este último bit é a verdadeira necessidade de volatile e pode torná -lo ideal, onde dois processos compartilham memória e precisam ler ou escrever sem bloqueio. Declarando uma variável como volatile é muito mais seguro neste contexto, forçando todos os programadores a usar Interlocked (que você não pode forçar pelo compilador).


EDIT: A citação a seguir fez parte da minha resposta original, vou deixar em ;-)

Uma citação do Linguagem de programação C# padrão:

Para campos não voláteis, as técnicas de otimização que consideram que as instruções de reordenação podem levar a resultados inesperados e imprevisíveis em programas multithreaded que acessam campos sem sincronização como o fornecido pelo estatamento de bloqueio. Essas otimizações podem ser executadas pelo compilador, pelo sistema de tempo de execução ou pelo hardware. Para campos voláteis, essas otimizações de reordenação são restritas:

  • Uma leitura de um campo volátil é chamada de leitura volátil. Uma leitura volátil possui: adquirir semântica "; isto é, é garantido que ocorre antes de qualquer referência à memória que ocorra após a sequência de instruções.

  • Uma escrita de um campo volátil é chamada de Escrita volátil. Uma escrita volátil tem "semântica de liberação"; isto é, é garantido que aconteça após qualquer referência de memória antes da instrução de gravação na sequência de instruções.

Atualizar: Pergunta reescrita amplamente, corrigiu minha resposta original e adicionou uma resposta "real"

Outras dicas

Este é um tópico bastante complexo. Eu encontro Joseph Albahari escrever ser uma das fontes mais definitivas e precisas para conceitos de multithreading na estrutura .NET que pode ajudar a responder sua pergunta.

Mas, para resumir rapidamente, há muita sobreposição entre o volatile palavra -chave e o Interlocked classe até onde eles podem ser usados. E, é claro, ambos vão muito acima e além do que você pode fazer com uma variável normal.

Sim - você pode olhar diretamente para o valor.

Contanto que você use apenas a classe interligada para acessar a variável, não há diferença. o que volátil O faz é que ele diz ao compilador que a variável é especial e, ao otimizar, não deve assumir que o valor não mudou.

Leva este loop:

bool done = false;

...

while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}

Se você definir done para true Em outro tópico, você esperaria que o loop saísse. No entanto - se feito não está marcado como volatile Então o compilador tem a opção de perceber que o código do loop nunca pode mudar done e pode otimizar a comparação para a saída.

Essa é uma das coisas difíceis sobre a programação multithread - muitas das situações que são problemas só surgem em determinadas situações.

Não vou tentar ser uma autoridade sobre esse assunto, mas eu recomendo que você dê uma olhada Este artigo pelo Jon Skeet.

Também dê uma olhada na parte final de esta resposta que detalha o quê volatile deve ser usado para.

Sim, você pode obter algum desempenho usando uma variável volátil em vez de um bloqueio.

O Lock é uma barreira completa da memória que pode fornecer as mesmas características de uma variável volátil, bem como de muitas outras. Como já foi dito, o volátil apenas garante que, em cenários com vários threads, se uma CPU alterar um valor em sua linha de cache, as outras CPUs virem o valor imediatamente, mas não garantem nenhuma semântica de travamento.

O problema é que o bloqueio é muito mais poderoso que o volátil e você deve usar o volátil quando pode evitar bloqueios desnecessários.

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