Depois de olhar para um monte de outras questões e suas respostas , fico com a impressão de que não há um acordo generalizado sobre o que a palavra-chave "volátil" em C significa exatamente.
Mesmo o próprio padrão não parece suficientemente claro para que todos concordem com o que isso significa .
Entre outros problemas:
- Parece fornecer garantias diferentes, dependendo do seu hardware e do seu compilador.
- Isso afeta as otimizações do compilador, mas não as otimizações de hardware; portanto, em um processador avançado que faz suas próprias otimizações em tempo de execução, não é claro se o compilador pode impedir a otimização que você deseja impedir. (Alguns compiladores geram instruções para impedir algumas otimizações de hardware em alguns sistemas, mas isso não parece ser padronizado de forma alguma.)
Para resumir o problema, parece (depois de ler muito) que "volátil" garante algo como: O valor será lido / gravado não apenas de / para um registro, mas pelo menos no cache L1 do núcleo, na mesma ordem em que as leituras / gravações aparecem no código. Mas isso parece inútil, já que a leitura / gravação de / para um registro já é suficiente no mesmo encadeamento, enquanto a coordenação com o cache L1 não garante mais nada em relação à coordenação com outros encadeamentos. Não consigo imaginar quando seria importante sincronizar apenas com o cache L1.
USO 1
O único uso amplamente aceito e volátil de sistemas voláteis parece ser para sistemas antigos ou embutidos em que determinados locais de memória são mapeados por hardware para funções de E / S, como um pouco na memória que controla (diretamente, no hardware) uma luz , ou um pouco na memória que informa se uma tecla do teclado está pressionada ou não (porque está conectada pelo hardware diretamente à tecla).
Parece que o "uso 1" não ocorre no código portátil cujos destinos incluem sistemas com vários núcleos.
USE 2
Não é muito diferente de "use 1" a memória que pode ser lida ou gravada a qualquer momento por um manipulador de interrupções (que pode controlar uma luz ou armazenar informações de uma tecla). Mas já para isso, temos o problema de que, dependendo do sistema, o manipulador de interrupções pode ser executado em um núcleo diferente com seu próprio cache de memória e "volátil" não garante a coerência do cache em todos os sistemas.
Portanto, o "uso 2" parece estar além do que o "volátil" pode oferecer.
USO 3
O único outro uso indiscutível que vejo é impedir a otimização incorreta dos acessos por meio de diferentes variáveis apontando para a mesma memória que o compilador não percebe que é a mesma memória. Mas isso provavelmente é indiscutível porque as pessoas não estão falando sobre isso - eu só vi uma menção a isso. E eu pensei que o padrão C já reconheceu que ponteiros "diferentes" (como argumentos diferentes para uma função) podem apontar para o mesmo item ou itens próximos, e já especifiquei que o compilador deve produzir código que funcione mesmo nesses casos. No entanto, não consegui encontrar rapidamente este tópico no padrão mais recente (500 páginas!).
Então "use 3" talvez não exista ?
Daí a minha pergunta:
"Volátil" garante alguma coisa no código C portátil para sistemas com vários núcleos?
EDIT - atualização
Depois de procurar o padrão mais recente , parece que a resposta é pelo menos um sim muito limitado:
1. O padrão especifica repetidamente o tratamento especial para o tipo específico "sig_atomic_t volátil". No entanto, o padrão também diz que o uso da função de sinal em um programa multithread resulta em comportamento indefinido. Portanto, esse caso de uso parece limitado à comunicação entre um programa de thread único e seu manipulador de sinais.
2. O padrão também especifica um significado claro para "volátil" em relação a setjmp / longjmp. (O exemplo de código onde é importante é fornecido em outras perguntas e respostas .)
Portanto, a pergunta mais precisa se torna:
"volátil" garante alguma coisa no código C portátil para sistemas com vários núcleos, além de (1) permitir que um programa de thread único receba informações de seu manipulador de sinal ou (2) permitir setjmp código para ver variáveis modificadas entre setjmp e longjmp?
Ainda é uma pergunta de sim / não.
Se "yes", seria ótimo se você pudesse mostrar um exemplo de código portátil sem erros que se tornaria buggy se "volatile" for omitido. Se "não", suponho que um compilador esteja livre para ignorar "volátil" fora desses dois casos muito específicos, para destinos com vários núcleos.
volatile
especificamente, o que acredito ser necessário.
volatile
informar o programa que ele pode ser alterado de forma assíncrona.