Y a-t-il un avantage d'utiliser le mot clé volatil en contraste pour utiliser la classe entre verrouillée?
-
19-09-2019 - |
Question
En d'autres termes, puis-je faire quelque chose avec une variable volatile qui ne pouvait pas également être résolue avec une variable normale et la classe entre verrouillée?
La solution
EDIT: Question largement réécrite
Pour répondre à cette question, j'ai plongé un peu plus loin en la matière et j'ai découvert quelques choses sur volatile
et Interlocked
que je n'étais pas au courant. Nettoyons cela, non seulement pour moi, mais pour cette discussion et d'autres personnes qui lisent ceci:
volatile
La lecture / écriture est censée être à l'abri de la réorganisation. Cette seulement signifie lire et écrire, ça fait ne pas signifier toute autre action;- volatilité n'est pas forcé sur le niveau de matériel CPU, c'est-à-dire (x86 utilise l'acquisition et la libération de clôtures sur n'importe quel lire écrire). Il empêche les optimisations du compilateur ou CLR;
Interlocked
utilise des instructions d'assemblage atomique pour compareexchange (cmpxchg
), Incrément (inc
) etc;Interlocked
utilise une serrure parfois: un Verrouillage matériel sur les systèmes multi-processeurs; Dans les systèmes uni-processor, il n'y a pas de verrouillage matériel;Interlocked
est différent devolatile
en ce qu'il utilise un clôture complète, où volatile utilise une demi-clôture.- Une lecture après une écriture peut être réorganisée Lorsque vous utilisez
volatile
. Ça ne peut pas arriver avecInterlocked
.VolatileRead
etVolatileWrite
Ayez le même problème de réorganisation que «Volatile (lien grâce à Brian Gideon).
Maintenant que nous avons les règles, nous pouvons définir une réponse à votre question:
- Techniquement: oui, il y a des choses que vous pouvez faire avec
volatile
que vous ne pouvez pas faire avecInterlocked
:- Syntaxe: vous ne pouvez pas écrire
a = b
oùa
oub
est volatile, mais c'est évident; - Vous pouvez lire une valeur différente après l'avoir rédigé sur une variable volatile en raison de la réorganisation. Vous ne pouvez pas faire ça avec
Interlocked
. En d'autres termes: vous pouvez être moins en sécurité avecvolatile
Alors tu peux être avecInterlocked
. - Performance:
volatile
est plus rapide alorsInterlocked
.
- Syntaxe: vous ne pouvez pas écrire
Sémantiquement: non, parce que
Interlocked
Fournit simplement un sur-ensemble d'opérations et est plus sûr à utiliser car il applique une clôture complète. Tu ne peux rien faire avecvolatile
que vous ne pouvez pas faire avecInterlocked
Et tu peux faire beaucoup avecInterlocked
que vous ne pouvez pas faire avec volatile:static volatile int x = 0; x++; // non-atomic static int y = 0; Interlocked.Increment(y); // atomic
Portée: oui, déclarant une variable
volatile
le rend volatil pour chaque accès. Il est impossible de forcer ce comportement autrementvolatile
ne peut pas être remplacé parInterlocked
. Ceci est nécessaire dans les scénarios où d'autres bibliothèques, interfaces ou matériels peuvent accéder à votre variable et la mettre à jour à tout moment, ou ont besoin de la version la plus récente.
Si vous me demandez, ce dernier est le réel besoin réel de volatile
et peut le rendre idéal lorsque deux processus partagent de la mémoire et doivent lire ou écrire sans verrouillage. Déclarant une variable comme volatile
est beaucoup plus sûr dans ce contexte, forçant tous les programmeurs à utiliser Interlocked
(que vous ne pouvez pas forcer par le compilateur).
Edit: La citation suivante faisait partie de ma réponse originale, je vais la laisser dans ;-)
Une citation du le C # Langage de programmation la norme:
Pour les champs non volatils, les techniques d'optimisation qui considèrent que les instructions de réorganisation peuvent conduire à des résultats inattendus et imprévisibles dans des programmes multithreads qui accèdent aux champs sans synchronisation tels que celui fourni par le statement de verrouillage. Ces optimisations peuvent être effectuées par le compilateur, par le système d'exécution ou par matériel. Pour les champs volatils, ces optimisations de réorganisation sont restreintes:
Une lecture d'un champ volatil est appelée un lecture volatile. Une lecture volatile a: acquérir la sémantique "; c'est-à-dire qu'elle est garantie avant toute référence à la mémoire qui se produit après sa séquence d'instructions.
Une écriture d'un champ volatil est appelée un Écriture volatile. Une écriture volatile a "libérer la sémantique"; Autrement dit, il est garanti de se produire après toutes les références de mémoire avant l'instruction d'écriture dans la séquence d'instructions.
Mise à jour: Question largement réécrite, corrigé ma réponse originale et a ajouté une réponse "réelle"
Autres conseils
C'est un sujet assez complexe. Je trouve que Joseph Albahari rédaction Être l'une des sources les plus définitives et les plus précises pour les concepts multithreading dans le framework .NET qui pourraient aider à répondre à votre question.
Mais, pour résumer rapidement, il y a beaucoup de chevauchement entre le volatile
mot-clé et le Interlocked
classe en ce qui concerne la façon dont ils peuvent être utilisés. Et bien sûr, les deux vont bien au-delà de ce que vous pouvez faire avec une variable normale.
Oui - vous pouvez regarder directement la valeur.
Tant que vous n'utilisez que la classe verrouillée pour accéder à la variable, il n'y a pas de différence. Quoi volatil Est-ce qu'il dit au compilateur que la variable est spéciale et lors de l'optimisation, il ne devrait pas supposer que la valeur n'a pas changé.
Prend cette boucle:
bool done = false;
...
while(!done)
{
... do stuff which the compiler can prove doesn't touch done...
}
Si vous définissez done
à true
Dans un autre fil, vous vous attendez à ce que la boucle quitte. Cependant - si cela n'est pas marqué comme volatile
Ensuite, le compilateur a la possibilité de réaliser que le code de boucle ne peut jamais changer done
Et il peut optimiser la comparaison pour la sortie.
C'est l'une des choses difficiles de la programmation multithread - de nombreuses situations qui sont des problèmes ne se présentent que dans certaines situations.
Je n'essaierai pas d'être une autorité à ce sujet, mais je vous recommande fortement de jeter un œil à Cet article par le vanté Jon Skeet.
Jetez également un œil à la dernière partie de Cette réponse qui détaille quoi volatile
doit être utilisé pour.
Oui, vous pouvez gagner des performances en utilisant une variable volatile au lieu d'une serrure.
Le verrouillage est une barrière de mémoire complète qui peut vous donner les mêmes caractéristiques d'une variable volatile ainsi que beaucoup d'autres. Comme il a déjà été dit volatile garantit que dans les scénarios multi-thread si un processeur modifie une valeur dans sa ligne de cache, les autres processeurs viennent immédiatement la valeur mais ne garantissent aucun sabot de verrouillage.
La chose est que le verrou est beaucoup plus puissant que volatile et vous devez utiliser volatile lorsque vous le pouvez pour éviter les verrous inutiles.