funciones integradas atómicas gcc

4 minutos de lectura

avatar de usuario
ddoman

http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Atomic-Builtins.html

Creo que el siguiente código aumenta el valor de var atómicamente.

volatile int var = 0;
__sync_fetch_and_add( &var, 1 )

Entendí los códigos anteriores como los siguientes lógica:

  1. Cargue la dirección de la variable var
  2. escriba el número 1 en la variable var atómicamente, a través del registro/caché, de alguna manera

Sin embargo, dudo que lo siguiente también sea atómico.

volatile int var = 0;
volatile int num = 1;
__sync_fetch_and_add( &var, num )

Dado que puede interpretarse como

  1. Cargue la dirección de la variable var
  2. Cargue el valor de la variable num en un registro
  3. escribe el valor en la variable var.

Después de que se ejecuta el #2, pero antes del #3, la CPU/subproceso se interrumpe y otra CPU/subproceso actualiza el valor de la variable num.

En otras palabras, al usar _sincronizar*() de gcc, ¿puedo usar una variable, no una constante, como segundo argumento?

¿No rompe la atomicidad?

avatar de usuario
dietrich epp

La operación es realmente dos operaciones.

__sync_fetch_and_add( &var, num )

Cargando num es atómico. agregándolo a var es atómico. Pero dos operaciones atómicas no hacen una operación atómica cuando se juntan. Por eso es tan difícil inventar nuevas estructuras de datos sin bloqueo. En general, dos operaciones seguras para subprocesos no necesariamente hacen una operación segura para subprocesos cuando se componen. Esta es la razón por la que es tan difícil hacer aplicaciones multiproceso correctas.

Verás, __sync_fetch_and_add es de hecho atómica, pero se comporta como una función ordinaria, por lo que toma el valor actual de “num” como parámetro. No es del todo correcto decir que la atomicidad de la función está rota, porque es responsabilidad de la persona que llama cargar el valor de num, y no es parte de la interfaz de la función. Igual podría quejarme de esto:

__sync_fetch_and_add(&var, some_really_long_function());

O peor,

__sync_fetch_and_add(long_function_1(), long_function_2());

Usted dice que “puede interpretarse como”

  1. Cargue la dirección de la variable var
  2. Carga el valor de la variable num
  3. Realiza la suma atómica

Pero de acuerdo con la especificación C, no es que mayo interpretarse de esta manera, sino más bien, deber interpretarse de esta manera, de lo contrario, el compilador no sería conforme (en realidad, podría intercambiar #1 y #2, pero eso no es importante aquí).

  • No diría que cargar num es atómico, porque sobrecarga el significado del trabajo atómico. Aquí lo usamos para indicar que no hay corte de palabras para cargas de enteros, pero también en el sentido de una operación atómica, por ejemplo, bloqueo de línea de caché entre las barreras del procesador de lectura y escritura.

    usuario82238

    16 de septiembre de 2012 a las 12:51

  • @BlankXavier: ¿Pero no es eso lo que significa atómico en general? En otras palabras, una operación atómica es aquella que ocurre por completo o no ocurre en absoluto, lo que se aplica a todas las cargas y almacenes alineados con palabras en muchas arquitecturas comunes. Parece que está hablando de garantías de orden (proporcionadas por barreras de memoria), que son un concepto diferente de la atomicidad: dos operaciones atómicas pueden parecer que ocurren en el orden opuesto de un proceso diferente, pero eso no significa que sean no atómico.

    -Dietrich Epp

    16 de septiembre de 2012 a las 13:31

  • Atómico en el sentido de barrera de memoria/bloqueo de línea de caché/LLSC es un conjunto de conceptos muy diferente y mucho más grande que atómico en el sentido de leer un entero simple y no ver la rotura de palabras. Pero la mayoría de la gente no sabe acerca de los problemas de barrera de memoria/etc. Creo que es confuso usar la misma palabra para ambos.

    usuario82238

    16 de septiembre de 2012 a las 14:15

  • No usamos la misma palabra para ambos: las operaciones atómicas son atómicas y las barreras de memoria son barreras de memoria, son conceptos diferentes con nombres diferentes. Sin embargo, las barreras de la memoria se pueden utilizar para crear ciertas operaciones atómicas a partir de operaciones atómicas más primitivas, y puede usar la operación atómica en combinación con barreras de memoria para crear primitivas de sincronización. La mayoría de las bibliotecas de operaciones atómicas incluyen operaciones atómicas con barreras adjuntas porque son muy útiles juntas, pero no son lo mismo.

    -Dietrich Epp

    2 oct 2012 a las 22:57


  • A partir de GCC 4.8, las funciones integradas de __sync han quedado obsoletas en favor de la función integrada de __atomic, dejando esto aquí para cualquiera que quiera usar __sync.

    – lucidbrot

    21 de octubre de 2017 a las 12:33


¿Ha sido útil esta solución?