Il est que vous connaissez le mot-clé volatile en principe Java de mise en uvre

avant-propos

Nous savons que le rôle du mot-clé volatile est entre plusieurs threads pour assurer la visibilité des variables, il est au cur du paquet java.util.concurrent, pas volatile pas de classes concurrentes pour notre utilisation.

Cet article détaille comment interpréter ce que le mot-clé volatile pour assurer la visibilité des variables entre plusieurs threads Avant cela, il est nécessaire d'expliquer la connaissance du cache du processeur, de maîtriser cette partie de la connaissance nous faire une meilleure compréhension du principe volatil, ainsi en utilisant mieux et avec plus de précision le mot-clé volatile.

cache CPU

cache du processeur apparaît principalement pour résoudre la vitesse du processeur et la vitesse d'accès mémoire ne correspond pas à la contradiction, parce que la vitesse de traitement du processeur est beaucoup plus rapide que la mémoire de lecture et une vitesse d'écriture, par exemple:

  • L'un des principaux accès à la mémoire est généralement des dizaines à des centaines de cycles d'horloge
  • Une cache d'écriture L1 nécessite seulement un ou deux cycles d'horloge
  • cache L2 est une écriture que des dizaines de besoin de cycles

Une différence significative de la vitesse d'accès, provoque la CPU peut prendre beaucoup de temps à attendre l'arrivée des données ou pour écrire des données à la mémoire.

Sur cette base, le lecteur est maintenant dans la plupart des cas ne sont pas accéder directement à la mémoire du processeur (CPU RAM ne sont pas connectés à la broche), est remplacé par le cache du processeur, le cache du processeur est une mémoire temporaire située entre la CPU et la mémoire, il Cependant, la capacité de mémoire plus petite que la mémoire est beaucoup plus rapide que la vitesse de commutation. Le cache de données est une petite partie des données en mémoire, mais ceci est une petite partie de la CPU est sur le point de visiter un peu de temps, lorsque le CPU appelle beaucoup de données, vous pouvez commencer à lire le cache, accélérant ainsi la vitesse de lecture.

Conformément à l'ordre de lecture comment étroitement lié à la CPU, la mémoire cache du processeur peut être divisé en:

  • Cache: Cache court L1, situé à côté du noyau du CPU, est combiné avec le cache du processeur CPU le plus étroitement
  • Acronyme moitié de cache L2, deux sous-interne et externe des puces, la puce mémoire cache secondaire même vitesse et de fréquence, la mémoire cache secondaire à puce externe, seule la fréquence de la vitesse: cache secondaire
  • cache à trois niveaux: appelé Cache L3, une CPU haut de gamme uniquement

Chacune des données stockées dans le cache sont tous une partie du cache, le coût de fabrication et la difficulté technique de ces trois est relativement diminue le cache, de sorte que sa capacité est relativement incréments.

Lorsque le processeur de lire des données, d'abord à partir d'un cache, sinon, trouver du cache secondaire, ou s'il n'y a pas de recherche à nouveau parmi les trois ou la mémoire cache. En général, chaque niveau a un taux de succès de cache d'environ 80%, ce qui signifie que 80% du montant total des données peut être trouvée dans le cache, la quantité totale de données que seulement 20% de celui-ci a besoin du cache secondaire, trois mémoire ou cache de lecture.

L'utilisation du cache du processeur apporté

Avec un mot d'image CPU- quelque chose > cache du processeur - > La relation entre la mémoire principale pour lire des données:

Lorsque le système est en marche, la CPU exécute le processus de calcul est la suivante:

  • Les programmes et les données sont chargées dans la mémoire principale
  • Les instructions et les données sont chargées dans le cache du processeur
  • l'exécution d'instructions du processeur, les résultats de cache écrits
  • write-back à la mémoire principale cache de données
  • Si le serveur est un processeur single-core, ces étapes n'ont pas de problèmes, mais si le serveur est CPU multi-core, la question est donc, de mettre en cache le modèle conceptuel processeur Intel Core i7 à titre d'exemple (photo prise « en profondeur la compréhension des systèmes informatiques « ):

    Imaginez la situation suivante:

  • Nuclear lire un octet 0, selon le principe de localisation, qui est également octets adjacents sont lus dans le coeur du cache 0
  • 3 nucléaire a fait le même travail ci-dessus, de sorte que le noyau nucléaire 0 et 3 ont les mêmes données de cache
  • 0 octets modify nucléaire qui, après avoir été modifié, les octets sont réécrites 0 cache nucléaire, mais ces informations ne sont réécrites à la mémoire principale
  • L'accès à l'âme 3 octets, parce que le noyau 0 ne sauvegarde pas de données d'écriture à la mémoire principale, les données ne sont pas synchronisées
  • Pour résoudre ce problème, les fabricants de CPU ont développé une règle: Quand un octet modifié cache CPU, d'autres CPU du serveur sera informé que leur cache sera considérée comme non valide. Ainsi, dans le cas ci-dessus, le noyau 3 se trouvent dans le cache de données est invalide, le noyau 0 va écrire immédiatement son propre retour de données à la mémoire principale, et le noyau 3 Relire les données.

    Java bytecode le démontage, le niveau assembleur pour voir ce qui a été fait sur le mot-clé volatile

    Avec la base théorique de ce qui précède, nous pouvons étudier comment mot-clé volatile à la fin est atteint. Tout d'abord, écrire un code simple:

  • / **
  • * @Author mai Changjei
  • * /
  • public   classe  LazySingleton {
  • privé   statique   volatil  = LazySingleton instance nul ;
  • public   statique  LazySingleton getInstance () {
  • si  (Instance == nul ) {
  • instance = nouveau  LazySingleton ();
  • }
  • retour  par exemple;
  • }
  • public   statique   vide  main (String args) {
  • LazySingleton.getInstance ();
  • }
  • }
  • D'abord, regardez le fichier du code décompilation, regardez la génération de code octet:

    Rien de spécial. Vous savez, les instructions de bytecode, comme la figure de getstatic, ifnonnull, nouveau, et correspondent en fin de compte au niveau du système d'exploitation, sont convertis en une seule instruction pour exécuter, machines de PC que nous utilisons, des serveurs d'applications d'architecture du processeur sont généralement est l'architecture IA-32, l'architecture de jeu d'instructions qui utilise une CISC (jeu d'instructions complexe), et le langage d'assemblage mnémonique est cet ensemble d'instructions.

    Par conséquent, étant donné que le niveau de bytecode, nous ne voyons pas d'indices, alors jetez un oeil sur le code suivant pour convertir les instructions de montage pourrait voir des indices. Le code de Windows ci-dessus pour voir le code assembleur correspondant est pas difficile (Tucao un, parler est facile, pour cette question que je cherchais toutes sortes d'informations, presque prêt à installer la machine virtuelle et engager dans un système Linux), hsdis d'accès les moyens de passage de l'outil de téléchargement direct puis extrait le téléchargement est terminé, et les hsdis-amd64.dll hsdis-amd64.lib deux fichiers peuvent être placés, au-dessous \ jre le chemin du serveur% JAVA_HOME% \ bin \:

    Ensuite, exécutez la fonction principale, avant d'exécuter la fonction principale, ajoutez les paramètres de la machine virtuelle suivants:

    -server -Xcomp -XX: + UnlockDiagnosticVMOptions -XX: + PrintAssembly -XX: CompileCommand = compileonly, * LazySingleton.getInstance

    Pour exécuter la fonction principale, les instructions de montage de génération de code:

  • Java HotSpot (TM) 64 bits avertissement serveur VM: PrintAssembly est activé, tourner sur DebugNonSafepoints pour gagner la sortie supplémentaire
  • CompilerOracle: compileonly * LazySingleton.getInstance
  • désassembleur Loaded de D: \ JDK \ jre \ bin \ server \ hsdis-amd64.dll
  • Décodage procédé compilé 0x0000000002931150:
  • code:
  • Argument 0 est unknown.RIP: Taille de code 0x29312a0: 0x00000108
  • # {Méthode} 'getInstance' '() LORG / XRQ / test / conception / singleton / LazySingleton,' dans 'org / XRQ / test / conception / singleton / LazySingleton'
  • #  (Sp de l'appelant)
  • 0x00000000029312a0: mov dword ptr , EAX
  • 0x00000000029312a7: pousser rbp
  • 0x00000000029312a8: sub rsp, 10H; * entrée de synchronisation
  • ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ -1 (ligne 13)
  • 0x00000000029312ac: mov r10,7ada9e428h; {oop (un 'java / lang / Class' = 'org / XRQ / test / conception / singleton / LazySingleton')}
  • 0x00000000029312b6: mov r11d, dword ptr
  • ; * Exemple Getstatic
  • ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 0 (ligne 13)
  • 0x00000000029312ba: Test r11d, r11d
  • 0x00000000029312bd: je 29312e0h
  • 0x00000000029312bf: mov r10,7ada9e428h; {oop (un 'java / lang / Class' = 'org / XRQ / test / conception / singleton / LazySingleton')}
  • 0x00000000029312c9: mov r11d, dword ptr
  • 0x00000000029312cd: mov rax, r11
  • 0x00000000029312d0: SHL rax, 3h; * exemple getstatic
  • ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 16 (ligne 17)
  • 0x00000000029312d4: add rsp, 10h
  • 0x00000000029312d8: RBP pop
  • 0x00000000029312d9: Test dword ptr , eax; {} poll_return
  • 0x00000000029312df: ret
  • 0x00000000029312e0: mov rax, QWORD ptr
  • 0x00000000029312e4: mov r10, rax
  • 0x00000000029312e7: add r10,10h
  • 0x00000000029312eb: cmp r10, QWORD ptr
  • 0x00000000029312ef: jnb 293135bh
  • 0x00000000029312f1: mov QWORD ptr , R10
  • 0x00000000029312f5: prefetchnta octet  ptr
  • 0x00000000029312fd: mov r11d, 0e07d00b2h; {oop ( 'org / XRQ / test / conception / singleton / LazySingleton')}
  • 0x0000000002931303: mov r10, QWORD ptr
  • 0x000000000293130b: mov QWORD ptr , R10
  • 0x000000000293130e: mov dword ptr , 0e07d00b2h
  • ; {Oop ( 'org / XRQ / test / conception / singleton / LazySingleton')}
  • 0x0000000002931315: mov dword ptr , R12d
  • 0x0000000002931319: mov RBP, rax; * nouveau  ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 6 (ligne 14)
  • 0x000000000293131c: mov RDX, RBP
  • 0x000000000293131f: appel 2907c60h; OopMap {RBP = Oop off = 132}
  • ; * Invokespecial < initialisation >
  • ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 10 (ligne 14)
  • ; {} Optimisation virtual_call
  • 0x0000000002931324: mov r10, RBP
  • 0x0000000002931327: SHR r10,3h
  • 0x000000000293132b: mov r11,7ada9e428h; {oop (un 'java / lang / Class' = 'org / XRQ / test / conception / singleton / LazySingleton')}
  • 0x0000000002931335: mov dword ptr , R10d
  • 0x0000000002931339: mov r10,7ada9e428h; {oop (un 'java / lang / Class' = 'org / XRQ / test / conception / singleton / LazySingleton')}
  • 0x0000000002931343: SHR r10,9h
  • 0x0000000002931347: mov r11d, 20b2000h
  • 0x000000000293134d: mov octet  ptr , R12l
  • 0x0000000002931351: Ajouter verrouillage dword ptr , 0h; * exemple putstatic
  • ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 13 (ligne 14)
  • 0x0000000002931356: JMP 29312bfh
  • 0x000000000293135b: mov RDX, 703e80590h; {oop ( 'org / XRQ / test / conception / singleton / LazySingleton')}
  • 0x0000000002931365: nop
  • 0x0000000002931367: appel 292fbe0h; OopMap {off = 204}
  • ; * nouveau  ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 6 (ligne 14)
  • ; {} Runtime_call
  • 0x000000000293136c: JMP 2931319h
  • 0x000000000293136e: mov RDX, rax
  • 0x0000000002931371: JMP 2931376h
  • 0x0000000002931373: mov RDX, rax; * nouveau  ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 6 (ligne 14)
  • 0x0000000002931376: add rsp, 10h
  • 0x000000000293137a: RBP pop
  • 0x000000000293137b: JMP 2932b20h; {} runtime_call
  • 0x0000000002931380: mov RBX, 0h; {} no_reloc
  • 0x000000000293138a: JMP 293138ah; {} runtime_call
  • 0x000000000293138f: JMP 292fca0h; {} runtime_call
  • 0x0000000002931394: appel 2931399h
  • 0x0000000002931399: sous QWORD ptr , 5H
  • 0x000000000293139e: JMP 2909000h; {} runtime_call
  • 0x00000000029313a3: HLT
  • 0x00000000029313a4: HLT
  • 0x00000000029313a5: HLT
  • 0x00000000029313a6: HLT
  • 0x00000000029313a7: HLT
  • Tant du code assembleur, vous ne savez pas où le CPU falsifié, rien est facile, accédez à 59,60 deux lignes:

  • 0x0000000002931351: Ajouter verrouillage dword ptr , 0h; * exemple putstatic
  • ; - org.xrq.test.design.singleton.LazySingleton :: getInstance @ 13 (ligne 14)
  • La raison pour laquelle est parce que le positionnement des deux lignes ici indiquent la fin d'une ligne 14, ligne 14 qui est l'affectation de variable d'instance locale volatile. Retour ajouter dword ptr Après, la compilation 0h des états sont normaux, ce qui signifie le pointeur de la pile à deux octets registre +0, la clé est d'ajouter serrure ici en face de l'instruction, une analyse détaillée du rôle de verrou derrière elle et pourquoi la boîte d'instruction instruction et serrure à garantie la visibilité de la mémoire du mot-clé volatile.

    instruction de verrouillage a

    Ont dit avant l'architecture IA-32, l'architecture du processeur sur la question qui nous intéresse peut vous vérifier, ici pour en savoir plus sur la description manuel d'instructions IA-32 de la serrure, aucun manuel IA-32 peut aller à cette adresse pour télécharger IA-32 Télécharger manuel, une version chinoise du manuel.

    Je extrait sur les manuels IA-32 qui décrivent le rôle de l'instruction sur la serrure (parce que le rôle des instructions de verrouillage dans le manuel éparpillés un peu partout, pas dit spécifiquement dans un chapitre ou une section):

    Lors de la modification des opérations de mémoire, le préfixe LOCK est utilisé pour appeler une lecture verrouillée - modification - opération d'écriture, ce mécanisme de communication fiable entre des processeurs dans un système multiprocesseur, décrit comme suit:

    (1) Au début des Pentium et les processeurs IA-32, génère un signal de verrouillage préfixe # LOCK fait que le processeur d'instructions en cours, ce qui provoque toujours un verrou de bus explicite se produit

    (2) Dans Pentium4, Inter processeurs Xeon série et P6, les opérations de verrouillage sont gérées par le verrouillage de bus de la mémoire cache ou verrous. S'il y a un accès à la mémoire cache et affecte une seule ligne de cache, l'opération est appelée un verrou de cache, sans être bloqué dans la mémoire du bus système et le système de la zone réelle. Pendant ce temps, d'autres Pentium4, Intel Xeon, ou processeurs de la série P6 sur cette écriture de bus de retour cache de données modifiées tous et les faire échouer, afin d'assurer la cohérence de la mémoire du système. Si aucun accès à la mémoire cache et / ou il couvre une limite de ligne de cache, le processeur produira signal LOCK #, et ne répond pas au bus pendant le fonctionnement de la demande de commande de verrouillage

    32 bits IA-32 supports de processeur d'une opération de mémoire de système atomes de zone verrouillée. Ces opérations sont utilisées pour gérer les structures de données partagées (comme sémaphores, descripteur, table de page système ou segment), deux ou plusieurs processeurs peuvent également être modifiés dans les mêmes données de domaine ou flag ces structures de données. Le processeur utilise un mécanisme permettant de mettre en oeuvre trois interdépendants verrouillé opérations atomiques:

    1, afin d'assurer que le fonctionnement atomique

    2, le verrouillage du bus, et en utilisant le signal de verrouillage # BLOCAGE préfixe d'instruction

    3, un protocole de cohérence de cache pour assurer l'exécution de l'opération atomique (verrouillage du cache) structure de données dans le cache. Ce mécanisme existe dans le Pentium4, Intel Xeon et les processeurs de la famille P6

    processeurs IA-32 est pourvu d'un signal LOCK #, il est activé automatiquement lors de certaines opérations de mémoire critique, pour verrouiller le bus système. Lorsque le signal de sortie délivré par le processeur de commande ou la demande d'un autre agent de bus est bloqué. D'autres applications logicielles peuvent être spécifiées par la sémantique requise préfixe LOCK LOCK est ajouté à l'avance avant l'instruction.

    Dans Intel386, Intel486, processeur Pentium instruction explicitement verrouillage entraînera le signal LOCK #. Un concepteur de matériel pour assurer la disponibilité du matériel du système, signal de verrouillage # pour contrôler l'accès à la mémoire entre les processeurs.

    Pour Pentinum4, Intel Xeon et les processeurs de la famille P6, si la zone de mémoire cache est accessible à l'intérieur du processeur, il est généralement pas question signal de verrouillage de #, bien au contraire, applique uniquement au cache du processeur de verrouillage.

    Est explicitement appliqué la sémantique LOCK, le logiciel peut être modifié dans la zone de mémoire d'instructions suivante en utilisant le préfixe LOCK. Lorsque le préfixe LOCK avant que d'autres instructions sont placées dans la mémoire ou l'instruction ne fait pas écriture (c.-à-destination opérande dans le registre), produisent une exception de codes d'opération illégal (#UD).

    [1] essai de bits et des instructions de modification (BTS, BTR, BTC)

    [2] l'instruction de permutation (XADD, cmpxchg, CMPXCHG8B)

    [3] assumer automatiquement l'instruction préfixe BLOCAGE a XCHG

    [4] en suivant les instructions simples opérande arithmétiques et logiques: INC, DEC, NOT, NEG

    [5] Les instructions arithmétiques et logiques suivantes nombre de double opération: ADD, ADC, SUB, SBB, AND, OR, XOR

    Une instruction de verrouillage veillera à ce que la zone de mémoire d'opérande de destination où le verrou, mais le système pourrait expliquer un peu plus grande zone fermé à clé.

    Le logiciel devrait utiliser la même adresse pour accéder à la longueur de l'opérande et de la quantité du signal (transmission de signal entre le processeur de la mémoire partagée utilisée). Par exemple, si un traitement de texte à utiliser pour accéder à un sémaphores, les autres processeurs ne devraient pas être utilisés pour accéder à un octet sémaphores.

    Pas de bus affecte l'intégrité de la zone de mémoire de verrouillage aligné. Le verrouillage de la sémantique continue de se réunir le nombre de cycles de bus nécessaires pour mettre à jour l'ensemble opérande. Toutefois, nous vous recommandons d'utiliser le verrouillage doit être aligné sur leurs frontières naturelles, afin d'améliorer les performances du système:

    Boundary [1] tout accès à 8 bits (verrouillé ou déverrouillé)

    16 frontière [2] pour accéder au mot verrouillé

    [3] verrouillage limite l'accès double mot de 32 bits

    64 limite [4] d'accès verrouillé à quatre caractères

    Pour toutes les autres opérations de mémoire et tous les événements extérieurs visibles, l'opération de verrouillage est atomique. Toutes les tables de pages et les opérations peuvent être verrouillées aller chercher sur l'instruction. Verrouillé instructions peuvent être utilisées pour synchroniser des données d'écriture du processeur et d'autres données lues fonctionnement du processeur.

    l'architecture IA-32 prévoit plusieurs mécanismes utilisés pour renforcer ou d'affaiblir le modèle de commande de mémoire pour gérer les situations de programmation spéciale. Ceux-ci comprennent:

    [1] instruction I / O, le verrouillage de commande, l'instruction sérialisée préfixe LOCK et analogues, pour forcer la commande forte sur un processeur

    [2] des instructions fournissent des capacités de tri SFENCE série et de certains types particuliers d'opérations de mémoire (introduites dans le Pentium III) et des instructions de LFENCE, des instructions de MFENCE (et des processeurs intégrés Pentium4 Intel Xeon)

    ... (Il y a aussi deux ne pas écrire)

    Ces mécanismes peuvent être utilisés de la manière suivante.

    Mappés en mémoire des dispositifs sur le bus, et d'autres unités I / O sont généralement très sensibles à leurs tampons d'écriture séquentielles, l'instruction I / O (instructions IN et OUT instruction) commandé de la manière suivante pour effectuer un tel solide opération d'écriture de l'accès . Avant d'effectuer un I / O instruction, le processeur attend jusqu'à ce que toutes les instructions sont terminés et tous les tampons sont la mémoire sont écrites. Seulement fetch et table de page recherche peut traverser les E / S des instructions, suivez les instructions pour attendre l'exécution d'instructions E / S est terminée avant de commencer.

    Ruminant instruction IA-32 manuel pour verrouiller le rôle de ces paragraphes la description, nous pouvons tirer plusieurs fonctions de commande verrouiller:

  • Verrouiller le bus, l'autre requêtes de lecture et d'écriture mémoire CPU sont bloquées jusqu'à ce que le verrou est libéré, mais les processeurs réels ultérieurs ont verrou de remplacement de verrouillage du cache du bus, le bus car la surcharge de verrouillage est relativement grande, l'autre CPU ne peut pas accéder à la période de verrouillage du bus mémoire
  • Après l'opération d'écriture de verrouillage rédigera données modifiées, tout en permettant une autre ligne de cache CPU correspondante est invalidée afin de recharger les dernières données de la mémoire principale
  • barrière de mémoire n'est pas en mesure d'effectuer une fonction similaire à la barrière de la mémoire, l'instruction de barrière empêche réordonnancement deux fois
  • (1) en raison de l'efficacité d'écriture, le verrouillage réel des processeurs plus tard ont la mémoire cache au lieu de bloquer le bus, en accord avec ce scénario et plus de données sont mises en cache par le protocole de cohérence de cache pour garantir que nous regardons ce qui est mis en cache, protocole de cohérence.

    protocole de cohérence de cache

    Avant de parler la cohérence du cache, d'abord parler du concept d'une ligne de cache:

    • cache segmentée (ligne) d'un segment correspondant à un espace de stockage, que nous appelons la ligne de cache, qui est la plus petite mémoire cache du processeur de l'unité peut être alloué, la taille de 32 octets, 64 octets, 128 octets allant ce dépendant de l'architecture du processeur, est généralement de 64 octets. Lorsque la CPU voir une instruction de lecture de la mémoire, l'adresse de mémoire qui sera transmis à un cache de données, un contrôle de cache de données pour voir si elle a cette adresse mémoire cache correspondant au segment, sinon mettre l'ensemble du segment du cache de la mémoire (ou le cache de niveau supérieur) est chargé. Notez ici que la première charge l'ensemble du segment de cache, ce qui est mentionné ci-dessus sur le principe de la localité

    Au-delà, # LOCK verrouille le bus, en fait, est irréaliste, car trop faible l'efficacité du bus de verrouillage. Par conséquent, il est préférable de le faire: utiliser plusieurs jeux de cache, mais leur comportement semble être un seul jeu de cache. protocole cache est conçu cohérence pour le faire, comme son nom l'indique, ce type d'accord est de faire plusieurs ensembles de cohérence du contenu mis en cache.

    Il existe une variété de protocole de cohérence de cache, mais la plupart du matériel informatique traitement quotidien sont « renifler (fouiner) » accord, son idée de base est le suivant:

    Tout transfert de mémoire se produit sur un bus partagé, et tout processeur peut voir ce bus: cache lui-même est indépendant, mais la mémoire est des ressources partagées, tous les accès mémoire passent par l'arbitrage (la même instruction le cycle, une seule CPU peut lire et écrire la mémoire cache).

    cache CPU traite non seulement avec le bus à temps pour faire le transfert de mémoire, mais les données conservées se produisant sur le reniflement d'échange de bus, suivi d'autres caches faire. Alors, quand un nom de cache du processeur, il appartient à lire et à la mémoire d'écriture, d'autres processeurs sont notifiés, afin de faire leur propre cache pour suivre le rythme. Tant qu'un processeur, une écriture de mémoire, d'autres processeurs savent immédiatement que la mémoire n'est plus valide dans leur segment de cache.

    protocole MESI est le plus courant du protocole de cohérence de cache, le protocole MESI, chaque ligne de cache a quatre états, représentés par le bit 2 est disponible, ils sont les suivants:

    Ici I, S et M ont le concept d'un état correspondant à: échec / non chargé, segment de cache propre et sale. Ainsi, ces nouvelles connaissances que l'état E, au nom d'un accès exclusif à l'Etat pour résoudre le « Avant de commencer à modifier un morceau de mémoire, nous devons dire aux autres processeurs, » cette question: que lorsque la ligne de cache est dans l'état E ou M le processeur peut écrire, que seulement dans ces deux états, le processeur est exclusif à cette ligne de cache. Lorsque le processeur d'écrire une ligne de cache, si elle ne dispose pas de droits exclusifs, il faut d'abord envoyer une demande « Je veux des droits exclusifs » au bus, qui informera l'autre processeur pour les copier ont l'échec même segment de cache ( Si là-bas). Seulement après avoir obtenu des droits exclusifs, le processeur peut commencer à modifier les données - et cette fois le savoir processeur que ce n'est une copie de la ligne de cache, dans mon propre cache, donc il n'y aura pas de conflits.

    A l'inverse, s'il y a d'autres processeurs que vous voulez lire la ligne de cache (bientôt savoir, comme cela a été le bus renifler), ligne de cache exclusive ou modifié doit d'abord revenir à l'état de « partage ». Si la ligne de cache est modifiée, il a mis aussi le contenu écrit de nouveau à la mémoire.

    En regardant en arrière à l'instruction de verrouillage pour lire et écrire des variables volatiles

    Je crois à l'interprétation de la serrure, la réalisation du principe du mot-clé volatile doit être claire de celui-ci. Premier coup d'oeil sur une carte:

    Le travail de mémoire est en fait la mémoire de travail des registres CPU et caches d'abstraction, ou chaque fil de la mémoire de travail peut être comprise simplement comme les registres CPU et les caches.

    Ensuite, lorsque le fil d'écriture et de deux fil-A Threab-B fonctionnent simultanément une variable de mémoire principale volatile i, une écriture de la variable Fil-A i, alors:

    • Thread Une commande BLOCAGE #
    • Vous pouvez verrouiller commande # bus (ligne ou cache de verrouillage) émis, tout en permettant le contenu de la ligne de cache dans le cache thread-B Défaut
    • écriture fil-A retour à la mémoire principale des changements récents i

    Discussion-B lit variable i, alors:

    • Discussion-B a trouvé une ligne de cache correspondant à l'adresse est verrouillée, en attendant la sortie de la serrure, le protocole de cohérence de cache veillera à ce que lit la dernière valeur

    On peut voir, lire et lire des variables ordinaires mot-clé volatile est fondamentalement aucune différence par rapport à la différence principalement dans les variables d'opération d'écriture.

    post-scriptum

    Avant le rôle du mot-clé volatile me confondre personnellement il y a quelques erreurs, après une connaissance approfondie du rôle du mot-clé volatile, se sentant une compréhension profonde de beaucoup volatile. Je crois que vous voyez l'article ici, tant que prêt à penser, prêt à étudier, me comme soudainement réalisé, le sentiment éclairé ^ _ ^

    Documents de référence

    • "IA-32 Architectures Software Developer est Manuel Volume 3: Guide de programmation du système"
    • « L'art de programmation Java en même temps »
    • « Compréhension en profondeur de la machine virtuelle Java: JVM fonctionnalités avancées et les meilleures pratiques. »
    • Voir PrintAssembly petite note volatile code assembleur
    • cohérence de mémoire cache (cache Coherency) Mise en route
    • Parlez de haute concurrence (trente-quatre) modèle de mémoire Java ces choses (b) comprendre le fonctionnement du cache du processeur

    Le nouvel iPhone sera publié, ou ne sont plus envoyés à l'adaptateur casque 3,5 mm! les téléphones Android emboîteront il?
    Précédent
    À voir forte 2698 yuans Meizu 16 images performances régresse, achèteriez-vous?
    Prochain
    classe Tuning | A Lita vit en Amérique du Nord comptent sur les petits bris de soutien-gorge exposée Diva coude beaucoup de filles
    Punir les yeux des problèmes sociaux, au deuxième trimestre, il montrera ses preuves!
    Acheté ces chaussures accessoires externes, à juste titre le changement de marée plus
    Couverture: 2018 Année Six Man US Cover
    158 stocks de volume lourds ont augmenté moins que le marché plus large
    été brillant -LMC 2019 série printemps et en été libérés
    anti-héros Marvel: avec des super pouvoirs innombrables d'acides gras oméga mutant niveau - grand
    "Spider-Man: Parallel Universe" sera une suite, Six-Handed Spider-Man devrait rejoindre!
    La plus récente et la performance du combiné Android classement, mil forte liste OV, Huawei gone
    Code n'est pas sûr! Avant d'aller au lit est pas configurer votre téléphone pour faire votre nouveau frauduleux « pas un cheveu de gauche ».
    méchant Marvel: des effets spéciaux de films et de télévision à super vilain - mystère invité
    « Soupe chinoise » à nouveau! La Chine est sur le point de Thompson 8 jours par les fans de la folle poursuite