Existe alguma vantagem de usar palavras -chave voláteis em contraste em usar a classe interligada?
-
19-09-2019 - |
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?
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 só 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 devolatile
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 comInterlocked
.VolatileRead
eVolatileWrite
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 fazerInterlocked
:- Sintaxe: você não pode escrever
a = b
Ondea
oub
é volátil, mas isso é óbvio; - 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 comvolatile
Então você pode estar comInterlocked
. - Atuação:
volatile
é mais rápido entãoInterlocked
.
- Sintaxe: você não pode escrever
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 comvolatile
que você não pode fazerInterlocked
E você pode fazer muito comInterlocked
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 porInterlocked
. 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.