registros programas lenguaje instrucciones explicados ensamblador ejemplos basicas c assembly x86-64 atomic

programas - ¿Cómo es que la instrucción INC de x86 no es atómica?



registros ax bx cx dx (3)

Esta pregunta ya tiene una respuesta aquí:

He leído que la instrucción INC de x86 no es atómica. Mi pregunta es ¿por qué? Supongamos que estamos incrementando un entero de 64 bits en x86-64, podemos hacerlo con una instrucción, ya que la instrucción INC funciona con las dos variables de memoria y el registro. Entonces, ¿cómo es que no es atómico?


¿Por qué sería? El núcleo del procesador aún necesita leer el valor almacenado en la ubicación de la memoria, calcular el incremento y luego almacenarlo nuevamente. Hay una latencia entre la lectura y el almacenamiento, y mientras tanto, otra operación podría haber afectado la ubicación de la memoria.

Incluso con la ejecución fuera de orden, los núcleos del procesador son lo suficientemente "inteligentes" para no tropezar con sus propias instrucciones y no serían responsables de modificar esta memoria en el intervalo de tiempo. Sin embargo, otro núcleo podría haber emitido una instrucción que modifica esa ubicación, una transferencia DMA podría haber afectado esa ubicación u otro hardware que haya tocado esa ubicación de memoria de alguna manera.


Los procesadores x86 modernos como parte de su proceso de ejecución "compilan" las instrucciones x86 en un conjunto de operaciones de nivel inferior; Intel llama a estos uOps, AMD rOps, pero a lo que se reduce es que cierto tipo de instrucciones x86 individuales se ejecutan por las unidades funcionales reales en la CPU en varios pasos .
Eso significa, por ejemplo, que:

INC EAX

se ejecuta como un solo "mini-op" como uOp.inc eax (déjame llamarlo así, no están expuestos).
Para otros operandos las cosas se verán de manera diferente, como:

INC DWORD PTR [ EAX ]

La descomposición de bajo nivel se vería más como:

uOp.load tmp_reg, [ EAX ] uOp.inc tmp_reg uOp.store [ EAX ], tmp_reg

Y por lo tanto no se ejecuta atómicamente. Si, por otro lado, prefieres decir LOCK INC [ EAX ] , eso indicará a la etapa de "compilación" de la tubería para que se descomponga de una manera diferente para garantizar que se cumpla el requisito de atomicidad.

La razón de esto es, por supuesto, como lo mencionan otros: la velocidad; ¿Por qué hacer algo atómico y necesariamente más lento si no siempre es requerido?


Realmente no desea una operación atómica garantizada a menos que la necesite, de los recursos de optimización de software de Agner Fog : instruction_tables.pdf (1996 - 2017):

Las instrucciones con un prefijo LOCK tienen una latencia prolongada que depende de la organización del caché y, posiblemente, de la velocidad de RAM. Si hay varios procesadores o núcleos o dispositivos de acceso directo a la memoria (DMA), todas las instrucciones bloqueadas bloquearán una línea de caché para el acceso exclusivo, lo que puede implicar el acceso a la RAM. Un prefijo LOCK suele costar más de cien ciclos de reloj, incluso en sistemas con un solo procesador. Esto también se aplica a la instrucción XCHG con un operando de memoria.