Question

Je sais que le modèle de mémoire .NET, les opérations (sur le .NET Framework non compact / micro / silverlight / mono / XNA / what-avez-vous) garantis que pour certains types (entiers plus particulièrement primitifs et références) ont été garantie être atomique.

En outre, je crois que le x86 / test-and-set instruction x64 (et Interlocked.CompareExchange) références en fait l'emplacement de mémoire globale, donc si elle succède à une autre Interlocked.CompareExchange verrait la nouvelle valeur.

Enfin, je crois que le mot-clé volatile est une instruction à compilateur Propager lit et écrit le plus tôt possible et de ne pas modifier l'ordre des opérations relatives à cette variable (à droite?).

Cela conduit à quelques questions:

  1. sont mes croyances rectiffent?
  2. Interlocked.Read n'a pas une surcharge pour int, uniquement pour les positions longues (qui sont 2 et sont donc MOTs pas lu normalement atomiquement). J'ai toujours pensé que le modèle de mémoire .NET garantit que la valeur la plus récente serait vu lors de la lecture ints / références, mais avec caches du processeur, registres, etc. Je commence à voir cela peut ne pas être possible. Ainsi est-il un moyen de forcer la variable à nouveau tirée par les cheveux?
  3. est volatile suffisante pour résoudre le problème ci-dessus pour les entiers et les références?
  4. Sur x86 / x64 je peux supposer que ...

S'il y a deux variables globales entières x et y, initialisées à 0 que si j'écris:

x = 1;
y = 2;

qu'aucun fil verra x = 0 et y = 2 (à savoir les écritures se produisent dans l'ordre). Est-ce que ce changement si elles sont volatiles?

Était-ce utile?

La solution

  • lit et écrit uniquement à des variables qui sont au plus 32 bits de large (et 64 bits de large sur les systèmes x64) sont atomiques. Tout cela signifie que vous ne lire un int et obtenir une valeur demi-écrite. Cela ne signifie pas l'arithmétique est atomique.
  • Les opérations emboîtés agissent également comme des barrières de mémoire, donc oui, Interlocked.CompareExchange verra la valeur actualisée.
  • Voir cette page . Volatile ne signifie pas ordonné. Certains compilateurs peuvent choisir de ne pas les opérations réordonner sur les variables volatiles, mais le CPU est libre de réordonner. Si vous voulez arrêter la CPU à partir d'instructions re-commande, utilisez une barrière de mémoire (complet).
  • Le modèle de mémoire garantit que les lectures et les écritures sont atomiques, et en utilisant le mot-clé volatile assure que les lectures seront toujours viennent de la mémoire, pas d'un registre. Donc, vous voir la valeur nouvelle. En effet, les processeurs x86 annulera le cache, le cas échéant - voir cette et cette . Aussi, voir InterlockedCompareExchange64 pour savoir comment atomiquement lire les valeurs de 64 bits.
  • Enfin, la dernière question. La réponse est un fil pourrait en fait voir x = 0 et y = 2, et en utilisant le mot-clé volatile ne change pas parce que le CPU est libre d'instructions réordonner. Vous avez besoin d'une barrière de mémoire.

Résumé:

  1. Le compilateur est libre d'instructions réordonner.
  2. La CPU est libre d'instructions réordonner.
  3. taille mot lectures et écritures sont atomiques. Arithmétique et d'autres opérations ne sont pas atomiques parce qu'ils impliquent une lecture, calcul, puis écrire.
  4. taille de la mémoire Word lit toujours récupérer la valeur nouvelle. Mais la plupart du temps vous ne savez pas si vous lisez en fait de la mémoire.
  5. Une barrière de mémoire pleine arrêt (1) et (2). La plupart des compilateurs vous permettent d'arrêter (1) par lui-même.
  6. Le mot-clé volatile vous assure lisiez de la mémoire - (4).
  7. Les opérations interverrouillées (le préfixe de verrouillage) permettent des opérations multiples de manière atomique. Par exemple, une écriture lu + (InterlockedExchange). Ou une lecture + écriture + comparer (InterlockedCompareExchange). Ils agissent également comme des barrières de mémoire, de sorte que (1) et (2) sont arrêtés. Ils écrivent toujours à la mémoire (évidemment), donc (4) est assurée.

Autres conseils

suis tombé sur ce vieux fil. Les réponses de Hans et wj32 sont tous corrects, sauf pour la partie en ce qui concerne volatile.

Plus précisément en ce qui concerne votre question

  

x86 / x64 je peux supposer que ... Si   il y a deux variables globales entières   x et y, à la fois initialisés à 0 que si   J'écris:   x = 1; y = 2;

     

Qu'aucune fil verra   x = 0 et y = 2 (à savoir les écritures seront   se produire dans l'ordre). Est-ce que ce changement si   ils sont volatils?

Si y est volatile, l'écriture à x est garantie avant de se produire à l'écriture y donc aucun fil ne verra jamais x = 0 et y = 2. En effet, la écriture à une variable volatile a la « libération sémantique » (logiquement équivalent à l'émission d'une clôture de libération), à savoir toutes les instructions de lecture / écriture avant qu'elle ne bouge pas passer. (Cela implique que si x est volatile mais y est pas, vous pouvez toujours voir le x = 0 inattendu et y = 2.) Voir l'exemple de description et le code dans la section C # spec pour plus de détails.

Non, le mot-clé volatile et la garantie de atomicité sont beaucoup trop faibles. Vous avez besoin d'une barrière de mémoire pour faire en sorte que. Vous pouvez en obtenir un explicitement la méthode Thread.MemoryBarrier ().

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