gcc x86 memory-barriers memory-order

gcc - diferencia en mfence y asm volatile(“”::: “memory”)



x86 memory-barriers (3)

Bueno, solo se necesita una barrera de memoria en las arquitecturas que tienen un orden de memoria débil. x86 y x64 no tienen un orden de memoria débil. en x86 / x64 todas las tiendas tienen una guía de liberación y todas las cargas tienen una guía de adquisición. entonces, solo deberías necesitar asm volatile ("" : : : "memory")

Para obtener una buena descripción general de Intel y AMD, así como referencias a las especificaciones del fabricante del evento, visite http://bartoszmilewski.com/2008/11/05/who-ordered-memory-fences-on-an-x86/

Generalmente, cosas como "volátil" se usan por campo, donde las cargas y los almacenes en ese campo son nativos atómicos. Donde las cargas y los almacenes a un campo ya son atómicos (es decir, la "operación" en cuestión es una carga o un almacén a un solo campo y, por lo tanto, toda la operación es atómica) el modificador de campo volatile o las barreras de memoria no son necesarias en x86 / x64 . Código portátil a pesar de.

Cuando se trata de "operaciones" que no son atómicas, por ejemplo, carga o almacena en un campo que es más grande que una palabra nativa o carga o almacena en múltiples campos dentro de una "operación", un medio por el cual se puede ver la operación Como atómico se requieren independientemente de la arquitectura de la CPU. Generalmente esto se hace por medio de una primitiva de sincronización como un mutex. Los Mutexes (los que he usado) incluyen barreras de memoria para evitar problemas como la reordenación del procesador para que no tenga que agregar instrucciones adicionales de barrera de memoria. En general, considero que no usar primitivas de sincronización una optimización prematura; pero, la naturaleza de la optimización prematura es, por supuesto, el 97% del tiempo :)

Cuando no usa una primitiva de sincronización y está lidiando con una invariante de campos múltiples, las barreras de memoria que aseguran que el procesador no reordena los almacenes y las cargas en diferentes ubicaciones de memoria son importantes.

Ahora, en términos de no emitir una instrucción "mfence" en asm volatile pero usar "memoria" en la lista de clobber. De lo que he podido read

Si las instrucciones de su ensamblador acceden a la memoria de una manera impredecible, agregue `memoria ''a la lista de registros comprimidos. Esto hará que GCC no mantenga los valores de la memoria caché en los registros a través de la instrucción del ensamblador y no optimice los almacenes o las cargas en esa memoria.

Cuando dicen "GCC" y no mencionan nada acerca de la CPU, esto significa que se aplica solo al compilador. La falta de "mfence" significa que no hay una barrera de memoria de la CPU. Puedes verificar esto desarmando el binario resultante. Si no se emite ninguna instrucción "mfence" (dependiendo de la plataforma de destino), está claro que no se le está diciendo a la CPU que emita una valla de memoria.

Dependiendo de la plataforma en la que se encuentre y de lo que esté tratando de hacer, tal vez haya algo "mejor" o más claro ... la portabilidad no se resista.

Por lo que he entendido, mfence es una barrera de memoria de hardware mientras que asm volatile ("" : : : "memory") mfence asm volatile ("" : : : "memory") es una barrera de compilación. Pero, se puede asm volatile ("" : : : "memory") ::: asm volatile ("" : : : "memory") en lugar de mfence.

La razón por la que me he confundido es este enlace.


Hay dos reordenamientos, uno es reordenar compilador, el otro es reordenar CPU.

x86 / x64 tiene un modelo de memoria relativamente fuerte, pero en x86 / x64 StoreLoad, la ordenación (las cargas posteriores que pasan a las tiendas anteriores) PUEDE suceder. ver http://en.wikipedia.org/wiki/Memory_ordering

  • asm volatile ("" ::: "memory") es solo una barrera del compilador.
  • asm volatile ("mfence" ::: "memory") es tanto una barrera de compilación como una barrera de CPU.

eso significa que, solo use una barrera de compilación, solo puede evitar la reordenación del compilador, pero no puede evitar la reordenación de la CPU. eso significa que no hay reordenación cuando se compila el código fuente, pero la reordenación puede ocurrir en tiempo de ejecución.

Por lo tanto, depende de sus necesidades, cuál utilizar.


  • asm volatile ("" ::: "memory") es solo una barrera del compilador.
  • asm volatile ("mfence" ::: "memory") es tanto una barrera de compilación como MFENCE
  • __sync_synchronize() también es una barrera de compilación y una barrera de memoria completa.

por lo que asm volatile ("" ::: "memory") no evitará que la CPU reordene las instrucciones de datos independientes en sí. Como se señaló, x86-64 tiene un fuerte modelo de memoria, pero aún es posible reordenar StoreLoad. Si se necesita una barrera de memoria completa para que funcione su algoritmo, entonces no __sync_synchronize