GCC ofrece un bonito conjunto de built-in functions para operaciones atómicas. Y al estar en MacOS o iOS, incluso Apple ofrece un nice set of atomic functions. Sin embargo, todas estas funciones realizan una operación, p. una suma/resta, una operación lógica (AND/OR/XOR) o un compare-and-set/compare-and-swap. Lo que estoy buscando es una manera de asignar atómicamente/leer un valor int
, como:Atomically read/write int value sin operación adicional en el valor int en sí
int a;
/* ... */
a = someVariable;
eso es todo. a
será leído por otro hilo y solo es importante que a
tenga su valor anterior o su valor nuevo. Lamentablemente, el estándar C no garantiza que asignar o leer un valor sea una operación atómica. Recuerdo que una vez leí en alguna parte, que escribir o leer un valor para una variable del tipo int
está garantizado que es atómico en GCC (independientemente del tamaño de int) pero busqué en todas partes en la página principal de GCC y no puedo encontrar esta declaración por más tiempo (tal vez fue eliminado).
No puedo usar sig_atomic_t
porque sig_atomic_t no tiene un tamaño garantizado y también puede tener un tamaño diferente de int
.
Dado que sólo un hilo jamás "escribir" un valor a a
, mientras que los dos hilos se "lee" el valor actual de a
, no es necesario que realice las operaciones a sí mismos de una manera atómica, por ejemplo:
/* thread 1 */
someVariable = atomicRead(a);
/* Do something with someVariable, non-atomic, when done */
atomicWrite(a, someVariable);
/* thread 2 */
someVariable = atomicRead(a);
/* Do something with someVariable, but never write to a */
Si ambos hilos iban a escribir en a
, entonces todas las operaciones tendrían que ser atómicas, pero de esa manera, esto solo podría desperdiciar tiempo de CPU; y somos extremadamente bajos en recursos de CPU en nuestro proyecto. Hasta ahora usamos un mutex alrededor de las operaciones de lectura/escritura de a
y aunque el mutex se mantiene por tan poco tiempo, esto ya causa problemas (uno de los hilos es un hilo en tiempo real y el bloqueo en un mutex hace que falle sus limitaciones en tiempo real, que es bastante malo).
Por supuesto que podría utilizar un __sync_fetch_and_add
para leer la variable (y simplemente añadir "0" a ella, a no modificar su valor) y para la escritura usar un __sync_val_compare_and_swap
para escribirlo (que yo sepa su valor anterior, por lo que pasa eso se asegurará de que el valor siempre se intercambie), pero ¿esto no agregará una sobrecarga innecesaria?
¿Cómo sé que no es más ancho que una palabra? ¿Pasando por ISO-C-99, que "tipo int" se define para ser siempre tan ancho como palabra? Por lo que puedo decir, esto no está garantizado para ningún tipo int; p.ej. en un microcontrolador de 8 bits, un int aún será de 16 bits, aunque el tamaño de la palabra sea de hecho de 8 bits. – Mecki
Un 'sig_atomic_t' debería funcionar, incluso si está destinado a algo completamente diferente (manejadores de señal). De todos modos, no creo que los backends del microcontrolador implementen '__sync_fetch_and_add', por lo que si los tomas en cuenta todas las apuestas están desactivadas. Se garantiza que –
'intptr_t' y' uintptr_t' typedefs son adecuados para almacenar un puntero, que generalmente es tan ancho como la palabra de máquina. –