c++ c++11 x86 arm compare-and-swap

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.