Je sais que le modèle de mémoire .NET (sur la framework .NET; non compact / micro / silverlight / mono / xna / what-a-vous-avez-vous) garantit que certains types (les entiers et références primitives et les références) étaient Garanti d'être atomique.
En outre, je crois que l'instruction de test X86 / x64 (et Enfin, je pense que le mot clé code> volatile code> est une instruction au compilateur em> à propager lit et écrit dès que possible et ne pas réorganiser les opérations concernant cette variable (non?). P> Ceci conduit à quelques questions: P> S'il y a deux variables entières globales x et Y, les deux initialisées à 0 que si j'écris: p> qu'aucun thread ne verra x = 0 et y = 2 (c'est-à-dire que les écritures se produiront dans l'ordre). Cela change-t-il si elles sont volatiles? P> p> interlocked.careeexchange code>) références réellement l'emplacement de la mémoire globale, donc si elle réussit un autre
Interlocked.careeexchange code> verrait la nouvelle valeur. P>
interlocked.Lead code> n'a pas de surcharge pour INT, uniquement pour les longs (qui sont 2 mots et ne sont donc normalement pas lus atomiquement). J'ai toujours supposé que le modèle de mémoire .NET garantissait que la valeur la plus récente serait vue lors de la lecture d'INT / références, cependant avec des caches de processeur, des registres, etc. Je commence à voir que cela peut ne pas être possible. Il y a donc un moyen de forcer la variable à être re-récupérée? LI>
3 Réponses :
Non, le mot clé volatile et la garantie d'atomicité sont beaucoup trop faibles. Vous avez besoin d'une barrière de mémoire pour vous assurer que. Vous pouvez obtenir un explicitement avec la méthode thread.memorybarrier (). P>
Ok ... cette réponse 2 et 3, mais qu'en est-il de # 4 (ordre dans lequel les threads verront des données)?
Aussi de: msdn.microsoft.com/en-us /Library/x13tttww7%28vs.71%29.aspx (URL LOL MSDN): "Le système lit toujours la valeur actuelle d'un objet volatil au point requis, même si l'instruction précédente a demandé une valeur du même objet. En outre, la valeur de l'objet est écrite immédiatement à l'affectation. Le modificateur volatil est généralement utilisé pour un champ accessible par plusieurs threads sans utiliser l'instruction de verrouillage pour sérialiser l'accès. L'utilisation du modificateur volatil garantit qu'un thread récupère la valeur la plus récente écrite par un autre fil. "
OH et le code d'exemple dans msdn.microsoft.com/ EN-US / Bibliothèque / AA645755% 28VS.71% 29.aspx - Cela semble contredire votre réponse.
L'article est faux. Vous ne me croirez pas, essayez-le pour vous-même.
interlocked.compeeexchange code> verra la valeur mise à jour. LI>
- See Cette page a>. Volatile ne signifie pas ordonné de commander. Certains compilateurs peuvent choisir de ne pas commander des opérations sur des variables volatiles, mais la CPU est libérée de rétrovisionnement. Si vous souhaitez arrêter la CPU des instructions de rétroéclairage, utilisez une barrière de mémoire (complète). Li>
- Le modèle de mémoire garantit que les lectures et les écritures sont atomiques et que l'utilisation du mot clé volatile garantit que lit toujours em> provenant de la mémoire, et non d'un registre. Donc, vous les em> voir la valeur la plus récente. En effet, X86 CPU invalidera le cache le cas échéant - voir Ce et
Ceci . Aussi, voir InterlockedcareExchange64 pour comment atomiquement Lisez les valeurs 64 bits. LI>
- et enfin, la dernière question. La réponse est un thread pourrait en fait voir
x = 0 code> et y = 2 code> et à l'aide du mot clé volatile ne change pas cela, car le CPU est libre de ré-commander instructions. Vous avez besoin d'une barrière de mémoire. Li>
ul>
Résumé: P>
- Le compilateur est libre d'obtenir des instructions de rétrovisionnement. LI>
- Le processeur est libre d'instructions de rétrovisionnement. Li>
- Les lectures de la taille des mots et les écritures sont atomiques. Les opérations arithmétiques et autres ne sont pas atomiques car elles impliquent une lecture, calculent, puis écrivez. LI>
- Les lectures de la taille des mots de la mémoire récupéreront toujours la valeur la plus récente. Mais la plupart du temps, vous ne savez pas si vous lisez en réalité de la mémoire. LI>
- Une barrière de mémoire complète s'arrête (1) et (2). La plupart des compilateurs vous permettent d'arrêter (1) par lui-même. Li>
- Le mot clé volatile vous assure que vous lisez de la mémoire - (4). LI>
- Les opérations verrouillées (le préfixe de verrouillage) permettent à plusieurs opérations d'être atomiques. Par exemple, une lecture + écriture (interlockedexchange). Ou une lecture + comparaison + écrire (interlockedconeExchange). Ils agissent également comme des barrières de mémoire, de sorte que (1) et (2) sont arrêtées. Ils écrivent toujours en mémoire (évidemment), donc (4) est assuré. Li>
ol>
Le problème avec la liaison à "C mythes clés dissipés" dans quelque chose à propos de .NET est qu'une source majeure de mythes sur volatile code> est des personnes qui font la même chose en C, C # et Java. En C #
volatile code> a en effet une certaine sémantique de commande selon msdn.microsoft.com/en-us/library/aa645755%28v=vs.71%29.aspx .
"Le fil pourrait en fait voir x = 0 et y = 2" - car .NET 2.0 Les opérations d'écriture ne peuvent pas être réorganisées.
est tombé sur ce vieux fil. Les réponses de HANS et WJ32 sont toutes correctes, à l'exception de la pièce concernant spécifiquement concernant votre question p>
sur x86 / x64 Puis-je supposer que ... si
Il y a deux variables globales entière
x et y, les deux initialisés à 0 que si si
J'écris:
qu'aucun fil ne verra
x = 0 et y = 2 (c'est-à-dire que les écritures seront
se produire dans l'ordre). Cela change-t-il si
ils sont volatils? P>
blockQuote>
si volatile code>. P>
x = 1; y = 2; code> p>
y code> est volatile, l'écriture sur
x code> est garantie avant que l'écriture sur
y code>, donc aucun fil ne verra jamais < Code> x = 0 code> et
y = 2 code>. En effet, l'écriture à une variable volatille a la "version sémantique" (logiquement équivalente à l'émission d'une clôture de libération), c'est-à-dire toutes les instructions de lecture / écriture avant qu'il ne se déplace pas. (Cela implique que si x est volatile, mais y n'est pas, vous pouvez toujours voir le
x = 0 code> et
y = 2 code>.) Voir l'exemple de description et de code dans le C # SPEC pour plus de détails. p>