Après la lecture de plusieurs blogs/articles etc, maintenant, je suis vraiment confus sur le comportement de load/store avant/après la barrière de mémoire.
Suivantes sont 2 des citations de Doug Lea dans l'un de ses clarification de l'article sur JMM, qui sont à la fois très compliqué:
- Tout ce qui était visible à enfiler quand il écrit à la volatilité du champ f devient visible pour le fil B lorsqu'il lit.f.
- Notez qu'il est important pour les deux threads d'accéder à la même volatilité variable afin de configurer correctement le passe-avant la relation. Ce n'est pas le cas, que tout ce qui est visible à enfiler lors de l'écriture du champ volatile f devient visible pour le fil B, après lecture champ volatile g.
Mais alors quand j'ai regardé dans un autre blog sur la mémoire de la barrière, j'ai eu ces:
- Un magasin de la barrière, "sfence" instruction sur x86, les forces de stocker toutes les instructions avant la barrière pour arriver avant la barrière et ont la stocker des tampons vidé le cache du PROCESSEUR sur lequel il est délivré.
- Une charge de la barrière, "lfence" instruction sur x86, les forces toutes les instructions de chargement après la barrière à se produire après la barrière, puis d'attendre le chargement de la mémoire tampon à égoutter pendant que le CPU.
Pour moi, Doug Lea clarification est plus stricte que les autres: fondamentalement, cela signifie que si la charge de la barrière et de stocker un obstacle sur les différents moniteurs, la cohérence des données ne sera pas garantie. Mais la plus tard l'un des moyens, même si les obstacles sont sur différents moniteurs, la cohérence des données sera garantie. Je ne suis pas sûr si je la compréhension de ces 2 correctement et aussi je ne suis pas sûr de qui est correct.
Considérant les codes suivants:
public class MemoryBarrier {
volatile int i = 1, j = 2;
int x;
public void write() {
x = 14; //W01
i = 3; //W02
}
public void read1() {
if (i == 3) { //R11
if (x == 14) //R12
System.out.println("Foo");
else
System.out.println("Bar");
}
}
public void read2() {
if (j == 2) { //R21
if (x == 14) //R22
System.out.println("Foo");
else
System.out.println("Bar");
}
}
}
Disons que nous avons 1 écrire fil TW1 le premier appel de la MemoryBarrier de la méthode write (), puis nous avons 2 threads de lecture de TR1 et TR2 appel MemoryBarrier de read1() et read2() la méthode.Estime que ce programme est exécuté sur un PROCESSEUR de ne pas préserver l'ordre (x86 FAIRE préserver l'ordre pour de tels cas, qui n'est pas le cas), selon le modèle de mémoire, il y aura un StoreStore barrière (disons SB1) entre W01/W02, ainsi que 2 LoadLoad barrière entre R11/R12 et R21/R22 (disons RB1 et RB2).
- Depuis SB1 et RB1 sont sur le même moniteur que j', fil TR1 qui appelle read1 devriez toujours voir 14 sur x, "Foo" est toujours imprimé.
- SB1 et RB2 sont sur différents moniteurs, si Doug Lea est correct, le fil TR2 ne sera pas assuré de voir 14 sur x, ce qui signifie "Bar" peut être imprimé à l'occasion. Mais si la mémoire de la barrière fonctionne comme Martin Thompson décrit dans le blog, la Boutique de la barrière de pousser toutes les données de la mémoire principale et de la Charge de la barrière va tirer toutes les données de la mémoire principale à cache/tampon, puis TR2 sera également assurée pour voir 14 sur x.
Je ne sais pas laquelle est la bonne, ou les deux d'entre eux sont, mais ce Martin Thompson décrit, c'est juste pour l'architecture x86. JMM ne garantit pas le changement de x est visible à TR2 mais x86 mise en œuvre.
Merci~