significa que prefijo postfijo operadores los incremento hay entre diferencias diferencia c++ c++11

c++ - que - ¿Cuál es la diferencia entre++, add operation y fetch_add() en atomic()



i++ java significa (3)

operator ++ no es una sola operación, pero 3 operaciones cargan add store, y por ej. en arm64 single load o almacen dos no generan ninguna valla de datos, la memoria de datos es más pequeña. for ex atomic_add 1 es un grupo de códigos con semántica de aquire / release

.LBB2_1: ldaxr x8, [x0] //load exclusive register with aquire add x8, x8, #1 stlxr w9, x8, [x0] //store with rlease cbnz w9, .LBB2_1 //if another thread changed value, try again

donde el operador ++ causará una condición de carrera si se usa de forma simulada por 2 hilos

ldr x8, [x0] add x8, x8, #1 // =1 str x8, [x0]

Ejecuté el siguiente código muchas veces, pero ¿por qué el resultado del incremento de prefijo, fetch_add () muestra el resultado correcto mientras que con la operación de adición (+), se imprime el resultado incorrecto?

#include <iostream> #include <mutex> #include <future> using namespace std; atomic <int> cnt (0); void fun() { for(int i =0; i <10000000 ; ++i) { //++cnt; // print the correct result 20000000 //cnt = cnt+1; // print wrong result, arbitrary numbers cnt.fetch_add(1); // print the correct result 20000000 } } int main() { auto fut1 = async(std::launch::async, fun); auto fut2 = async(std::launch::async, fun); fut1.get(); fut2.get(); cout << "value of cnt: "<<cnt <<endl; }


++cnt y cnt.fetch_add(1) son operaciones verdaderamente atómicas. Un hilo se bloquea mientras el otro hilo lee, incrementa y actualiza el valor. Como tal, los dos hilos no pueden pisar los dedos de los pies. El acceso a cnt está completamente serializado, y el resultado final es el que usted esperaría.

cnt = cnt+1; No es completamente atómico. Implica tres operaciones separadas, solo dos de las cuales son atómicas, pero una no lo es. Cuando un hilo ha leído atómicamente el valor actual de cnt e hizo una copia local, el otro hilo ya no está bloqueado y puede modificar libremente cnt a voluntad mientras se incrementa esa copia . Luego, la asignación de la copia incrementada a cnt se realiza de forma atómica, pero se asignará un valor obsoleto si cnt ya ha sido modificado por el otro hilo. Así que el resultado final es aleatorio y no lo que se esperaría.


cnt = cnt+1

Esta no es una operación atómica. Esto primero carga cnt en una operación atómica, luego hace la suma y finalmente almacena el resultado en otra operación atómica. Sin embargo, el valor puede cambiarse después de la carga, que puede ser sobrescrito por la tienda final, lo que conduce a un resultado final incorrecto.

Los otros dos son operaciones atómicas y por lo tanto evitan tal condición de carrera.

Tenga en cuenta que, el operador ++, --, +=, -=, &=, |=, ^= están sobrecargados en std::atomic para proporcionar operaciones atómicas.