c++ - ¿Las operaciones CAS atómicas en x86_64 y ARM siempre usan std:: memory_order_seq_cst?
c++11 compare-and-swap (3)
Creo que el compilador emite el lock cmpxchg
incluso para memory_order_relaxed
porque esa es la única manera de asegurarse de que el intercambio compare + sea en realidad atómico. Como artless_noise dijo en los comentarios, otras arquitecturas pueden usar Load Linked / Store Conditional para implementar compare_exchange_weak(...)
.
memory_order_relaxed
debería permitir al compilador memory_order_relaxed
otras variables fuera de bucles y, de lo contrario, reordenar el acceso a la memoria en tiempo de compilación.
Si había una manera de hacerlo en x86 que no era también una barrera de memoria completa, un buen compilador lo usaría para memory_order_relaxed
.
Como Anthony Williams dijo :
some_atomic.load (std :: memory_order_acquire) simplemente pasa a una instrucción de carga simple, y some_atomic.store (std :: memory_order_release) pasa a una simple instrucción de almacenamiento.
Se sabe que en x86 para las operaciones load()
y store()
memory barriers memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel
no requiere instrucciones del procesador.
Pero en ARMv8 sabíamos que aquí hay barreras de memoria tanto para load()
como para store()
: http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic- Weapons-1-of-2 http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-2-of-2
Acerca de las diferentes arquitecturas de CPU: http://g.oswego.edu/dl/jmm/cookbook.html
A continuación, pero para la operación CAS en x86 , estas dos líneas con diferentes barreras de memoria son idénticas en el código Desmontaje ( MSVS2012 x86_64 ):
a.compare_exchange_weak(temp, 4, std::memory_order_seq_cst, std::memory_order_seq_cst);
000000013FE71A2D mov ebx,dword ptr [temp]
000000013FE71A31 mov eax,ebx
000000013FE71A33 mov ecx,4
000000013FE71A38 lock cmpxchg dword ptr [temp],ecx
a.compare_exchange_weak(temp, 5, std::memory_order_relaxed, std::memory_order_relaxed);
000000013FE71A4D mov ecx,5
000000013FE71A52 mov eax,ebx
000000013FE71A54 lock cmpxchg dword ptr [temp],ecx
Código de desensamblaje compilado por GCC 4.8.1 x86_64 - GDB :
a.compare_exchange_weak(temp, 4, std::memory_order_seq_cst, std::memory_order_seq_cst);
a.compare_exchange_weak(temp, 5, std::memory_order_relaxed, std::memory_order_relaxed);
0x4613b7 <+0x0027> mov 0x2c(%rsp),%eax
0x4613bb <+0x002b> mov $0x4,%edx
0x4613c0 <+0x0030> lock cmpxchg %edx,0x20(%rsp)
0x4613c6 <+0x0036> mov %eax,0x2c(%rsp)
0x4613ca <+0x003a> lock cmpxchg %edx,0x20(%rsp)
Está en plataformas x86 / x86_64 para cualquier operación CAS atómica, un ejemplo como este atomic_val.compare_exchange_weak(temp, 1, std::memory_order_relaxed, std::memory_order_relaxed);
siempre satisfecho con el orden std::memory_order_seq_cst
?
Y si cualquier operación CAS en el x86 siempre se ejecuta con consistencia secuencial ( std::memory_order_seq_cst
) independientemente de las barreras, ¿entonces en el ARMv8 es lo mismo?
PREGUNTA: ¿Debería el orden de std::memory_order_relaxed
para CAS
bus de memoria CAS
block en x86 o ARM?
RESPUESTA: En x86, cualquier operación de compare_exchange_weak()
con std::memory_orders
(incluso std::memory_order_relaxed
) siempre se traduce en LOCK CMPXCHG
con bloqueador de bus, para ser realmente atómico , y tener igual valor para XCHG
- "el cmpxchg
es igual que costoso como la instrucción xchg
" .
(Una adición: XCHG
igual a LOCK XCHG
, pero CMPXCHG
no es igual a LOCK CMPXCHG
(que es realmente atómico)
En ARM y PowerPC para cualquier `compare_exchange_weak () para diferentes std :: memory_orders hay diferentes instrucciones de procesador de bloqueo , a través de LL / SC .
Processor memory-barriers-instructions para x86 (excepto CAS), ARM y PowerPC: http://www.cl.cam.ac.uk/~pes20/cpp/cpp0xmappings.html
No debe preocuparse por las instrucciones que el compilador asigna a un constructo C11 dado, ya que no captura todo. En su lugar, debe desarrollar código con respecto a las garantías del modelo de memoria C11. Como se observa en el comentario anterior, el compilador o compiladores futuros pueden reordenar operaciones de memoria relajadas siempre que no violen el modelo de memoria C11. También vale la pena ejecutar su código a través de una herramienta como CDSChecker para ver qué comportamientos están permitidos en el modelo de memoria.
x86 garantiza que se soliciten las cargas que siguen a las cargas y se solicitan las tiendas siguientes. Dado que CAS requiere tanto la carga como el almacenamiento, todas las operaciones deben ordenarse a su alrededor.
Sin embargo, vale la pena señalar que, en presencia de átomos múltiples con memory_order_relaxed, el compilador puede reordenarlos. No puede hacerlo con memory_order_seq_cst.