Après avoir examiné un tas d' autres questions et leurs réponses , j'ai l'impression qu'il n'y a pas de consensus sur ce que signifie exactement le mot clé "volatile" en C.
Même la norme elle-même ne semble pas assez claire pour que tout le monde s'entende sur ce qu'elle signifie .
Entre autres problèmes:
- Il semble offrir différentes garanties en fonction de votre matériel et de votre compilateur.
- Cela affecte les optimisations du compilateur mais pas les optimisations matérielles, donc sur un processeur avancé qui fait ses propres optimisations au moment de l'exécution, il n'est même pas clair si le compilateur peut empêcher toute optimisation que vous souhaitez empêcher. (Certains compilateurs génèrent des instructions pour empêcher certaines optimisations matérielles sur certains systèmes, mais cela ne semble en aucune façon standardisé.)
Pour résumer le problème, il apparaît (après avoir lu beaucoup) que "volatile" garantit quelque chose comme: La valeur sera lue / écrite non seulement depuis / vers un registre, mais au moins vers le cache L1 du noyau, dans le même ordre que les lectures / écritures apparaissent dans le code. Mais cela semble inutile, car la lecture / écriture depuis / vers un registre est déjà suffisante dans le même thread, tandis que la coordination avec le cache L1 ne garantit rien de plus concernant la coordination avec les autres threads. Je ne peux pas imaginer quand il pourrait être important de synchroniser uniquement avec le cache L1.
UTILISATION 1
La seule utilisation largement acceptée de volatile semble être pour les systèmes anciens ou intégrés où certains emplacements de mémoire sont mappés matériellement aux fonctions d'E / S, comme un bit en mémoire qui contrôle (directement, dans le matériel) une lumière , ou un peu en mémoire qui vous indique si une touche du clavier est enfoncée ou non (car elle est connectée directement par le matériel à la touche).
Il semble que «utiliser 1» ne se produit pas dans le code portable dont les cibles incluent les systèmes multicœurs.
UTILISATION 2 La
mémoire qui peut être lue ou écrite à tout moment par un gestionnaire d'interruption (qui peut contrôler une lumière ou stocker des informations à partir d'une clé) n'est pas trop différente de "utiliser 1". Mais déjà pour cela, nous avons le problème que, selon le système, le gestionnaire d'interruption peut s'exécuter sur un cœur différent avec son propre cache mémoire , et "volatile" ne garantit pas la cohérence du cache sur tous les systèmes.
Donc, "utiliser 2" semble aller au-delà de ce que "volatile" peut offrir.
UTILISATION 3
La seule autre utilisation incontestée que je vois est d'empêcher une mauvaise optimisation des accès via différentes variables pointant vers la même mémoire que le compilateur ne réalise pas est la même mémoire. Mais cela n'est probablement incontesté que parce que les gens n'en parlent pas - je n'en ai vu qu'une mention. Et je pensais que la norme C reconnaissait déjà que des pointeurs "différents" (comme différents arguments vers une fonction) pouvaient pointer vers le même élément ou des éléments voisins, et j'ai déjà spécifié que le compilateur devait produire du code qui fonctionne même dans de tels cas. Cependant, je n'ai pas pu trouver rapidement ce sujet dans la dernière norme (500 pages!).
Donc, "utiliser 3" n'existe peut-être pas du tout?
D'où ma question:
Est-ce que "volatile" garantit quoi que ce soit dans le code C portable pour les systèmes multicœurs?
EDIT - mise à jour
Après avoir parcouru la dernière norme , il semble que la réponse soit au moins un oui très limité:
1. La norme spécifie à plusieurs reprises un traitement spécial pour le type spécifique "sig_atomic_t volatile". Cependant, la norme indique également que l'utilisation de la fonction de signal dans un programme multithread entraîne un comportement indéfini. Ce cas d'utilisation semble donc limité à la communication entre un programme monothread et son gestionnaire de signaux.
2. La norme spécifie également une signification claire pour "volatile" par rapport à setjmp / longjmp. (Un exemple de code là où c'est important est donné dans d'autres questions et réponses .)
La question la plus précise devient donc:
«volatile» garantit-il quoi que ce soit dans le code C portable pour les systèmes multicœurs, à l'exception de (1) autoriser un programme à thread unique à recevoir des informations de son gestionnaire de signal, ou (2) autoriser setjmp code pour voir les variables modifiées entre setjmp et longjmp?
C'est toujours une question oui / non.
Si "oui", ce serait bien si vous pouviez montrer un exemple de code portable sans bogue qui devient bogué si "volatile" est omis. Si "non", alors je suppose qu'un compilateur est libre d'ignorer "volatile" en dehors de ces deux cas très spécifiques, pour les cibles multicœurs.
volatile
précisément ce qui, à mon avis, est nécessaire.
volatile
d'informer le programme qu'il peut changer de manière asynchrone.