Comment fonctionnent les barrières de mémoire?

J’ai besoin de comprendre les barrières de mémoire dans les machines multicœurs. Dis que j’ai ce code

Core 1

mov [_x], 1; mov r1, [_y] 

Core 2

 mov [_y], 1; mov r2, [_x] 

Maintenant, les résultats inattendus sans barrière de mémoire seraient que r1 et r2 peuvent être égaux à 0 après exécution. À mon avis, pour remédier à ce problème, nous devrions placer une barrière de protection dans les deux codes, car ne le régler que sur un code ne résoudrait pas le problème. Quelque chose comme ce qui suit …

Core 1

 mov [_x], 1; memory_fence; mov r1, [_y] 

Core 2

 mov [_y], 1; memory_fence; mov r2, [_x] 

Ma compréhension est-elle correcte ou manque-t-il encore quelque chose? Supposons que l’architecture est x86. De plus, quelqu’un peut-il me dire comment insérer une barrière de mémoire dans un code C ++?

Les clôtures sérialisent l’opération qu’elles clôturent (chargements et magasins), c’est-à-dire qu’aucune autre opération ne peut commencer avant que la clôture ne soit exécutée, mais la clôture ne s’exécutera pas tant que toutes les opérations précédentes ne seront pas terminées. citer intel rend le sens de ceci un peu plus précis (extrait de l’instruction MFENCE, page 3-628, vol. 2A, référence de l’instruction Intel):

Cette opération de sérialisation garantit que chaque instruction de chargement et de stockage qui précède l’instruction MFENCE dans l’ordre du programme devient globalement visible avant toute instruction de chargement ou de stockage qui suit l’instruction MFENCE.1

  1. Une instruction de chargement est considérée comme globalement visible lorsque la valeur à charger dans son registre de destination est déterminée.

Utiliser des clôtures en C ++ est délicat (C ++ 11 peut avoir une sémantique de clôture quelque part, peut-être que quelqu’un d’autre a des informations à ce sujet), car il dépend de la plate-forme et du compilateur. Pour les architectures x86 utilisant MSVC ou ICC, vous pouvez utiliser _mm_lfence , _mm_sfence & _mm_mfence pour charger, stocker et charger + clôturer (notez que certaines d’entre elles sont des instructions SSE2).

Remarque: cela suppose une perspective Intel, c’est-à-dire: utilisant un processeur x86 (32 ou 64 bits) ou IA64

C ++ 11 ( ISO / IEC 14882: 2011 ) définit un modèle de mémoire multithreading. Bien que je ne connaisse aucun compilateur qui implémente actuellement le nouveau modèle de mémoire, C ++ Concurrency in Action d’Anthony Williams le documente très bien. Vous pouvez consulter le Chapitre 5 – Modèle de mémoire C ++ et Opérations sur les types atomiques où il explique les opérations assouplies et les barrières de mémoire. Il est également l’auteur de la bibliothèque just :: thread qui peut être utilisée jusqu’à ce que le fournisseur du compilateur prenne en charge le nouveau standard. just :: thread est la base de la bibliothèque boost :: thread.