Pourquoi ne volatils existent?
Ce qui ne l' volatile
mot-clé le faire? En C++ ce problème permet-il de résoudre?
Dans mon cas, je n'ai jamais sciemment besoin.
- Voici une discussion intéressante sur la volatilité en ce qui concerne le pattern Singleton: aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
- Il est un intrigant technique qui rend votre compilateur de détecter d'éventuelles conditions de course qui s'appuie fortement sur le mot clé volatile, vous pouvez la lire http://www.ddj.com/cpp/184403766.
- C'est une belle ressource avec un exemple sur quand
volatile
peut être utilisé de manière efficace, les mettre ensemble dans un joli termes simples. Lien : publications.gbdirect.co.royaume-uni/c_book/chapter8/... - Je l'utilise pour verrouiller le code/la double vérification de verrouillage
- Pour moi,
volatile
plus utile quefriend
mot-clé.
Vous devez vous connecter pour publier un commentaire.
volatile
est nécessaire si vous lisez à partir d'un endroit en mémoire que, disons, un tout autre processus/périphérique/tout ce que peut écrire à.J'ai l'habitude de travailler avec dual-port ram dans un système multiprocesseur à droite C. Nous avons utilisé un matériel gérés 16 bits valeur d'un sémaphore de savoir quand l'autre gars a été fait. Essentiellement, nous l'avons fait:
Sans
volatile
, l'optimiseur voit dans la boucle inutile (Le gars ne définit jamais la valeur! Il est fou, se débarrasser de ce code!) et mon code, de procéder sans avoir acquis le sémaphore, à l'origine des problèmes plus tard.uint16_t* volatile semPtr
a été écrit à la place? Ce devrait marquer le pointeur comme volatile (au lieu de la valeur pointée), de sorte que vérifie le pointeur lui-même, par exemple,semPtr == SOME_ADDR
ne peut pas être optimisé. Toutefois, cela implique un volatile valeur indiquée à nouveau ainsi. Non?*semPtr
?std::atomic
, votre seule option est de pirater les choses vous-même avec l'asm inline ou de la bibliothèque des appels de fonction de tout les obstacles. Vous pouvez rassembler la volatilité de l'accès à unread_once()
fonction ou une macro comme le noyau Linux n', mais il serait encore bouillir jusqu'à présent pour obtenir de l'asm que vous voulez sur n'importe quel sane mise en œuvre où l'alignement devolatile uint16_t
peut être lu/écrit de manière atomique. (c'est à dire sur la plupart des plates-formes spécifiques, le comportement réel que vous obtenez à partir de ce qui est bien défini.)atomic<uint16_t>
ouvolatile atomic<uint16_t>
à faire acquérir des-charges. Dans ce cas, le compilateur ne pouvais pas le levage de la charge, car que ferait la boucle infinie, de sortevolatile
n'est pas nécessaire ici. Peut et ne le compilateur d'optimiser les deux atomique des charges?)volatile
est nécessaire, sous certaines conditions. Mais ce n'est pas le cas. Prenons l'exemple d'une plate-forme qui fournit un type natif, direatomic_int
, qui est documenté pour être adapté à la lecture de la mémoire qui a complètement séparé périphériques peuvent écrire. Certainementvolatile
ne serait pas nécessaire sur cette plate-forme. Parce que c'est très souvent le cas, dans la pratique,volatile
est que très rarement nécessaire, même lorsque vous avez besoin de ce comportement.volatile
est nécessaire lors de l'élaboration de systèmes embarqués ou à des pilotes de périphérique, où vous avez besoin de lire ou d'écrire un périphérique matériel mappé en mémoire. Le contenu d'un périphérique particulier registre pourrait changer à tout moment, si vous avez besoin de lavolatile
mot-clé afin de s'assurer que ces accès ne sont pas optimisé par le compilateur.Certains processeurs ont registres virgule flottante qui ont plus de 64 bits de précision (par exemple. 32-bit x86 sans l'ESS, voir Pierre du commentaire). De cette façon, si vous exécutez plusieurs opérations sur les nombres double précision, vous obtenez en fait une plus grande précision de réponse que si vous étiez à tronquer chaque résultat intermédiaire à 64 bits.
C'est généralement grand, mais cela signifie que, en fonction de la manière dont le compilateur attribué registres et ne optimisations, vous aurez des résultats différents pour les mêmes opérations sur exactement les mêmes entrées. Si vous avez besoin de cohérence, alors vous pouvez forcer chaque opération pour revenir à la mémoire en utilisant le mot clé volatile.
Il est également utile pour certains algorithmes, qui n'ont pas de sens algébrique, mais de réduire à virgule flottante erreur, comme Kahan sommation. Algebraicly c'est un nop, il sera souvent incorrectement optimisé à moins que certaines variables intermédiaires sont volatiles.
volatile double
au lieu de simplementdouble
, de sorte à s'assurer qu'il est tronqué à partir de la FPU, la précision de 64 bits (RAM) précision avant de poursuivre les calculs. Les résultats ont été sensiblement différents en raison d'une poursuite de l'exagération de la virgule flottante d'erreur.g++ -mfpmath=sse
de l'utiliser pour 32-bit x86 ainsi. Vous pouvez utilisergcc -ffloat-store
à force d'arrondi partout même lors de l'utilisation de x87, ou vous pouvez définir la x87 précision de 53 bits de mantisse: randomascii.wordpress.com/2012/03/21/....volatile
à force d'arrondi dans quelques lieux sans perdre les avantages de partout.À partir d'un "Volatile comme une promesse" article de Dan Saks:
Voici des liens pour trois de ses articles concernant la
volatile
mot-clé:Vous DEVEZ utiliser volatils lors de la mise en œuvre sans verrouillage des structures de données. Sinon le compilateur est libre pour optimiser les accès à la variable, qui va changer la sémantique.
Pour le dire autrement, la volatilité indique au compilateur que l'accès à cette variable doit correspondre à une mémoire physique opération de lecture/écriture.
Par exemple, c'est comment InterlockedIncrement est déclaré dans l'API Win32:
std::atomic<LONG>
de sorte que vous pouvez écrire lockless code plus sûr et sans problèmes de l'avoir pur charges / pure magasins optimisé loin, ou réorganisés, ou tout autre chose.Une grande application que j'ai l'habitude de travailler sur dans le début des années 1990 contient C-exception basée sur la manipulation à l'aide de setjmp et longjmp. Le mot clé volatile a été nécessaire sur les variables dont les valeurs doivent être préservés dans le bloc de code qui a servi comme la "prise" de la clause, de peur que ceux vars être stockées dans les registres et anéanti par le longjmp.
En C Standard, l'un des lieux de l'utilisation
volatile
est avec un gestionnaire de signal. En fait, en C Standard, tout ce que vous pouvez faire en toute sécurité dans un gestionnaire de signal est de modifier unvolatile sig_atomic_t
variable, ou d'en sortir rapidement. En effet, autant que je sache, c'est le seul endroit dans la Norme C que l'utilisation devolatile
est nécessaire pour éviter un comportement indéfini.Qui signifie que dans le Standard C, vous pouvez écrire:
et pas grand chose d'autre.
POSIX est beaucoup plus indulgent sur ce que vous pouvez faire dans un gestionnaire de signal, mais il y a encore des limitations (et l'une des limitations est que le Standard de la bibliothèque d'e/S —
printf()
et al — ne peut être utilisé en toute sécurité).Développement de systèmes embarqués, j'ai une boucle qui vérifie sur une variable qui peut être changé dans un gestionnaire d'interruption. Sans "volatile", la boucle devient un noop - ce que le compilateur ne peut pas savoir, la variable ne change jamais, il optimise la case de distance.
Même chose devrait s'appliquer à une variable qui peut être changé dans un thread différent dans une approche plus traditionnelle de l'environnement, mais il y a souvent, nous n'synchronisation des appels, de sorte que le compilateur n'est pas si libre avec l'optimisation.
Je l'ai utilisé dans les versions de débogage lorsque le compilateur insiste sur l'optimisation de loin une variable que je veux être en mesure de voir que je code pas à pas.
Outre son utilisation comme prévu, la volatilité est utilisé dans (modèle) métaprogrammation. Il peut être utilisé pour empêcher l'activation accidentelle de la surcharge, comme la volatilité de l'attribut (comme const) participe à la résolution de surcharge.
C'est légal; les deux surcharges sont potentiellement exigible à vue et font presque le même. Le casting de la
volatile
surcharge est légal comme nous le savons bars ne passe pas non volatileT
de toute façon. Levolatile
version est strictement pire, mais, si jamais choisi dans la résolution de surcharge si le non-volatilef
est disponible.Noter que le code ne jamais dépend en réalité de
volatile
d'accès à la mémoire.La
volatile
mot-clé est destinée à empêcher le compilateur de l'application de toutes les optimisations sur les objets qui peuvent changer dans les moyens qui ne peuvent être déterminées par le compilateur.Des objets déclarés comme
volatile
sont omis de l'optimisation, parce que leurs valeurs peuvent être modifiés par le code de l'extérieur de la portée de l'actuel code à tout moment. Le système lit toujours la valeur actuelle d'unvolatile
objet à partir de l'emplacement de mémoire plutôt que de les conserver sa valeur dans le registre temporaire au point où il est demandé, même si une instruction précédente demandé une valeur à partir d'un même objet.Envisager les cas suivants
1) les variables Globales modifié par une routine de service d'interruption en dehors de la portée.
2) les variables Globales au sein d'une application multi-thread.
Si nous n'utilisons pas de volatiles qualificatif, les problèmes suivants peuvent survenir
1) du Code ne peut pas fonctionner comme prévu lorsque l'optimisation est activée.
2) du Code ne peut pas fonctionner comme prévu lorsque les interruptions sont activées et utilisées.
Volatile: Un programmeur est le meilleur ami de
https://en.wikipedia.org/wiki/Volatile_(computer_programming)
À côté du fait que le mot clé volatile est utilisé pour dire au compilateur de ne pas optimiser l'accès à une variable (qui peut être modifié que par un fil ou une routine d'interruption), il peut également être utilisé pour enlever les quelques bugs du compilateur -- OUI, il peut être ---.
Par exemple, j'ai travaillé sur une plate-forme intégrée ont été le compilateur a été faire quelques mauvais assuptions concernant la valeur d'une variable. Si le code n'est pas optimisé le programme s'exécuter sur ok. Avec les optimisations (qui étaient vraiment besoin parce que c'était une critique de routine) le code ne fonctionnerait pas correctement. La seule solution (bien que pas très correct), a été de déclarer la 'défectueux' variable volatile.
Votre programme semble fonctionner même sans
volatile
mot-clé? C'est peut-être la raison:Comme déjà mentionné, la
volatile
mot-clé aide pour les cas commeMais il semble y avoir pratiquement aucun effet une fois, externe ou non en ligne de la fonction est appelée. E. g.:
Alors avec ou sans
volatile
presque le même résultat est généré.Aussi longtemps que g() peut être complètement incorporé, le compilateur peut voir tout ce qui se passe et peuvent ainsi optimiser. Mais lorsque le programme fait appel à un endroit où le compilateur ne peut pas voir ce qu'il se passe, il n'est pas sûr pour le compilateur de faire des hypothèses plus. Donc le compilateur génère un code qui lit toujours à partir de la mémoire directement.
Mais méfiez-vous de la journée, quand votre fonction g() devient inline (soit explicite de changements ou en raison de compilateur/linker intelligence), puis votre code peut se briser si vous avez oublié le
volatile
mot-clé!Donc je vous conseille d'ajouter de la
volatile
mot-clé, même si votre programme semble fonctionner sans. Il fait l'intention plus claire et plus robuste à l'égard des changements futurs.volatile
qualifié de pointeur de fonction:void (* volatile fun_ptr)() = fun; fun_ptr();
Dans les premiers jours de C, les compilateurs d'interpréter toutes les actions que lire et écrire des lvalues que les opérations de mémoire, pour être exécutée dans la même séquence que le lit et écrit est apparu dans le code. L'efficacité pourrait être grandement améliorée dans de nombreux cas, si les compilateurs ont donné un certain montant de la liberté de ré-ordonner et de consolider les activités, mais il y a un problème avec cela. Même les opérations ont souvent été spécifié dans un certain ordre simplement parce qu'il était nécessaire de les spécifier dans certains, et donc le programmeur choisi l'une des nombreuses également de bonnes alternatives, que ce n'était pas toujours le cas. Parfois, il serait important que certaines opérations se produire dans un ordre particulier.
Exactement les détails de séquençage sont importants variera en fonction de la plate-forme cible et domaine d'application. Plutôt que de fournir particulièrement détaillées de contrôle, la Norme a opté pour un modèle simple: si une séquence d'accès sont fait avec des lvalues qui ne sont pas qualifiés
volatile
, un compilateur peut réorganiser et de les consolider, comme il l'entend. Si une action est menée avec unevolatile
qualifiés lvalue, une qualité de mise en œuvre devrait offrir tout autre des garanties de classement pourrait être requis par le code de ciblage de sa plate-forme et le champ d'application, sans avoir à exiger l'utilisation de la non-standard de la syntaxe.Malheureusement, plutôt que d'identifier quelles garanties les programmeurs ont besoin, de nombreux compilateurs ont plutôt opté pour offrir le minimum de garanties mandaté par la Norme. Cela rend
volatile
beaucoup moins utile qu'elle ne devrait l'être. Sur gcc ou clang, par exemple, un programmeur d'avoir à mettre en œuvre une base de "hand-off mutex" [celui où une tâche qui a acquis et a publié un mutex de ne pas le faire à nouveau jusqu'à ce que l'autre a fait] doit faire l'une des quatre choses:Mis l'acquisition et la libération du mutex dans une fonction, le compilateur ne peut pas inline, et à laquelle il ne peut pas s'appliquer pour l'Ensemble du Programme d'Optimisation.
Qualifier tous les objets gardé par le mutex comme
volatile
--quelque chose qui ne devrait pas être nécessaire si tous les accès se produire après l'acquisition du mutex et avant de le relâcher.Utilisez l'optimisation de niveau 0 pour forcer le compilateur à générer du code, comme si tous les objets qui ne sont pas qualifiés
register
sontvolatile
.Utiliser gcc-directives particulières.
En revanche, lors de l'utilisation d'une plus grande qualité de compilateur, ce qui est plus approprié pour la programmation de systèmes, tels que la cpi, on aurait une autre option:
volatile
qualifiés écriture est réalisé everyplace une acquisition ou de la libération est nécessaire.L'acquisition d'une base "hand-off mutex" nécessite un
volatile
lire (à voir si c'est prêt), et ne doit pas nécessiter unvolatile
écrire ainsi (de l'autre côté de ne pas essayer d'acquérir de nouveau jusqu'à ce qu'il est remis à l'arrière), mais d'avoir à effectuer un sensvolatile
écrire, c'est toujours mieux que l'une des options disponibles en vertu de la gcc ou clang.Une utilisation, je dois vous rappeler est, dans le gestionnaire de signal fonction, si vous souhaitez consulter/modifier une variable globale (par exemple, le marquer comme sortie = true), vous devez déclarer cette variable comme "volatile".