Y a-t-il un avantage d'utiliser le mot clé volatil en contraste pour utiliser la classe entre verrouillée?

StackOverflow https://stackoverflow.com/questions/1701216

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?

Était-ce utile?

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 de volatile 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 avec Interlocked. VolatileRead et VolatileWrite 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 avec Interlocked:
    1. Syntaxe: vous ne pouvez pas écrire a = ba ou b est volatile, mais c'est évident;
    2. 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é avec volatile Alors tu peux être avec Interlocked.
    3. Performance: volatile est plus rapide alors Interlocked.
  • 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 avec volatile que vous ne pouvez pas faire avec Interlocked Et tu peux faire beaucoup avec Interlocked 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 autrement volatile ne peut pas être remplacé par Interlocked. 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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top