Réponses:
Pour des gains de performances, les processeurs modernes exécutent souvent des instructions dans le désordre pour utiliser au maximum le silicium disponible (y compris les lectures / écritures de mémoire). Comme le matériel applique l'intégrité des instructions, vous ne remarquez jamais cela dans un seul thread d'exécution. Cependant, pour plusieurs threads ou environnements avec mémoire volatile (E / S mappées en mémoire par exemple), cela peut conduire à un comportement imprévisible.
Une clôture / barrière de mémoire est une classe d'instructions qui signifie que les lectures / écritures de mémoire se produisent dans l'ordre que vous attendez. Par exemple, une «clôture complète» signifie que toutes les lectures / écritures avant la clôture sont validées avant celles après la clôture.
Notez que les clôtures de mémoire sont un concept matériel. Dans les langages de niveau supérieur, nous sommes habitués à traiter des mutex et des sémaphores - ceux-ci peuvent bien être implémentés en utilisant des barrières de mémoire au bas niveau et l'utilisation explicite de barrières de mémoire n'est pas nécessaire. L'utilisation de barrières de mémoire nécessite une étude approfondie de l'architecture matérielle et se trouve plus fréquemment dans les pilotes de périphériques que dans le code d'application.
La réorganisation du processeur est différente des optimisations du compilateur - bien que les artefacts puissent être similaires. Vous devez prendre des mesures distinctes pour empêcher le compilateur de réorganiser vos instructions si cela peut provoquer un comportement indésirable (par exemple, l'utilisation du mot-clé volatile en C).
Copier ma réponse à une autre question, quelles sont les astuces qu'un processeur fait pour optimiser le code? :
Le plus important serait la réorganisation des accès mémoire.
En l'absence de barrières mémoire ou d'instructions de sérialisation, le processeur est libre de réorganiser les accès mémoire. Certaines architectures de processeur ont des restrictions sur la quantité de réapprovisionnement; Alpha est connu pour être le plus faible (c'est-à-dire celui qui peut le plus réorganiser).
Un très bon traitement du sujet peut être trouvé dans la documentation source du noyau Linux, à Documentation / memory-barrières.txt .
La plupart du temps, il est préférable d'utiliser des primitives de verrouillage de votre compilateur ou de votre bibliothèque standard; ceux-ci sont bien testés, doivent avoir toutes les barrières mémoire nécessaires en place, et sont probablement assez optimisés (l'optimisation des primitives de verrouillage est délicate; même les experts peuvent parfois se tromper).
Alpha is known for being the weakest
, pourquoi weakest
? N'est-il pas mieux que, il réorganise plus, donc ce sera une exécution beaucoup plus rapide? (Je ne suis pas un utilisateur alpha, mais je demande l'effet de very reordering
vs restricted reordering
). Alors, quels sont les inconvénients de la réorganisation des lots (à l'exception du risque de comportement indéfini, mais je suppose que la plupart des processeurs modernes auraient dû résoudre une bonne réorganisation et implémenter uniquement une réorganisation définie, sinon cela n'aurait pas de sens de la décision qu'ils ont prise).
Dans mon expérience, cela fait référence à une barrière de mémoire , qui est une instruction (explicite ou implicite) pour synchroniser l'accès à la mémoire entre plusieurs threads.
Le problème se produit dans la combinaison de compilateurs agressifs modernes (ils ont une liberté incroyable pour réorganiser les instructions, mais ne savent généralement rien de vos threads) et de processeurs multicœurs modernes.
Une bonne introduction au problème est la déclaration " Le verrouillage double est cassé" " Le ". Pour beaucoup, c'était le réveil qu'il y avait des dragons.
Les barrières implicites de mémoire pleine sont généralement incluses dans les routines de synchronisation des threads de plate-forme, qui en couvrent le cœur. Cependant, pour la programmation sans verrouillage et l'implémentation de modèles de synchronisation légers et personnalisés, vous n'avez souvent besoin que de la barrière, voire d'une barrière à sens unique.
La barrière de mémoire, également connue sous le nom de membre ou barrière de mémoire, est une classe d'instructions qui amènent une unité centrale de traitement (CPU) à appliquer une contrainte d'ordre sur les opérations de mémoire émises avant et après l'instruction de barrière.
Les processeurs utilisent des optimisations de performances qui peuvent entraîner une exécution dans le désordre, y compris des opérations de chargement et de stockage de la mémoire. La réorganisation des opérations de mémoire passe normalement inaperçue dans un seul thread d'exécution, mais provoque un comportement imprévisible dans les programmes concurrents et les pilotes de périphériques à moins d'être soigneusement contrôlés. La nature exacte d'une contrainte d'ordre dépend du matériel et est définie par le modèle de mémoire de l'architecture. Certaines architectures fournissent de multiples barrières pour appliquer différentes contraintes de commande.
Les barrières de mémoire sont généralement utilisées lors de l'implémentation d'un code machine de bas niveau qui fonctionne sur la mémoire partagée par plusieurs périphériques. Ce code comprend des primitives de synchronisation et des structures de données sans verrouillage sur des systèmes multiprocesseurs et des pilotes de périphériques qui communiquent avec du matériel informatique.