smcdow
En mi caja de Linux, sig_atomic_t
es un simple viejo int
. Hacer ints
posee una cualidad atómica especial?
$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
...
Thread model: posix
gcc version 4.3.2 (Debian 4.3.2-1.1)
$ echo '#include <signal.h>' | gcc -E - | grep atomic
typedef int __sig_atomic_t;
typedef __sig_atomic_t sig_atomic_t;
zwol
C99 sig_atomic_t
se ajusta sólo a una definición muy débil de “atomicidad”, porque C99 no tiene concepto de concurrencia, sólo interrumpibilidad. (C2011 agrega un modelo de concurrencia, y con él el _Atomic
tipos que hacen garantías más fuertes; sin embargo, AFAIK sig_atomic_t
no ha cambiado, ya que su razón de ser todavía hay comunicación con los manejadores de señales, no a través de subprocesos).
Esto es todo lo que dice C99 sobre sig_atomic_t
:
(§7.14
<signal.h>
párrafo 2) El tipo definido essig_atomic_t
, que es el tipo entero (posiblemente calificado como volátil) de un objeto al que se puede acceder como una entidad atómica, incluso en presencia de interrupciones asíncronas. (§7.14<signal.h>
Párrafo 2)(§7.14p5) Si [a] la señal se produce de otra manera que no sea el resultado de llamar al
abort
oraise
función, el comportamiento no está definido si el controlador de señal se refiere a cualquier objeto con duración de almacenamiento estático que no sea asignando un valor a un objeto declarado comovolatile sig_atomic_t
.(§7.18.3 Límites de otros tipos de enteros, párrafo 3) Si
sig_atomic_t
(ver 7.14) se define como un tipo entero con signo, el valor deSIG_ATOMIC_MIN
no será mayor que −127 y el valor deSIG_ATOMIC_MAX
no será inferior a 127; de lo contrario, sig_atomic_t se define como un tipo entero sin signo, y el valor deSIG_ATOMIC_MIN
será 0 y el valor deSIG_ATOMIC_MAX
no será inferior a 255.
El término “entidad atómica” no se define en ninguna parte del estándar. Traduciendo de los estándares-ese, el intención es que la CPU puede actualizar completamente una variable de tipo sig_atomic_t
en la memoria (“duración de almacenamiento estático”) con una instrucción de máquina. Por lo tanto, en la máquina abstracta C99 sin concurrencia y precisamente interrumpible, es imposible que un controlador de señal observe una variable de tipo sig_atomic_t
a la mitad de una actualización. El lenguaje §7.18.3p3 permite que este tipo sea tan pequeño como char
si necesario. Tenga en cuenta por favor el ausencia completa de cualquier idioma relacionado con la coherencia entre procesadores.
Hay CPU reales que requieren más de una instrucción para escribir un valor mayor que char
a la memoria También hay CPU reales que requieren más de una instrucción para escribir valores más pequeño que una palabra de máquina (a menudo, pero no necesariamente, lo mismo que int
) a la memoria. El lenguaje en el manual de la biblioteca GNU C ahora es inexacto. Representa un deseo por parte de los autores originales de eliminar lo que vieron como una licencia innecesaria para que las implementaciones de C hicieran cosas raras que hacían la vida más difícil para los programadores de aplicaciones. Desafortunadamente, esa misma licencia es lo que hace posible tener C en algunas máquinas reales. Hay al menos un puerto Linux incorporado (al AVR) para el cual ninguno int
ni los punteros se pueden escribir en la memoria en una instrucción. (La gente está trabajando para hacer que el manual sea más preciso, ver, por ejemplo, http://sourceware.org/ml/libc-alpha/2012-02/msg00651.html — sig_atomic_t
Sin embargo, parece haberse perdido en ese.)
-
Je, parece que no. Probablemente estaría mejor con algo más pequeño 🙂 Sin embargo, tiendo a pensar que Linux/AVR con cualquier biblioteca C es más probable que sea un objetivo de portabilidad relevante hoy en día que Hurd u otros sistemas operativos boutique pero no integrados.
– zwol
7 de marzo de 2012 a las 20:12
-
Ok, entonces asumiré que el manual de glibc no es inexacto. (Observe que dice: En la práctica y esto es cierto en todas las máquinas que admite la biblioteca GNU C)
– ninjalj
7 de marzo de 2012 a las 20:18
-
Tenga en cuenta que
sig_atomic_t
no hace nada para que las operaciones de lectura, modificación y escritura sean atómicas con respecto a las señales. En x86, las interrupciones no se pueden dividirdec dword [mem]
, por lo que es atómico en un núcleo Uniprocessor con respecto a las interrupciones, o un proceso de subproceso único con respecto a las señales de la segunda mitad de esta respuesta. Pero (AFAIK) no hay una forma ISO o GNU C11 de solicitar esonum--
compila a eso en lugar de insns de carga/almacenamiento separados, sin usar un atómico que compilará alock dec dword [num]
. Sin contar el asm en línea, por supuesto.– Peter Cordes
9 sep 2016 a las 17:14
-
Solo para ser específicos sobre las limitaciones.: tampoco tiene control sobre el reordenamiento en tiempo de compilación, y el compilador asume que el objeto no se modifica de forma asíncrona. (Entonces
while(updated_by_sig_handler == 0){}
puede compilar aif(update_by_sig_handler == 0){ while(true); }
en lugar de un bucle que vuelve a leer la memoria dentro del bucle, hasta que ve un valor escrito por un controlador de señal. O levante la carga de un bucle que hace algo mientras espera. Escribir bucles de espín usted mismo casi siempre es malo, incluso si usa átomos C11, pero es un ejemplo fácil).– Peter Cordes
9 sep 2016 a las 17:22
-
Ah, claro, vi este idioma en el estándar, pero no me detuve para entenderlo. Y por supuesto tiene que ser
volatile
, derp, eso desencadena la suposición de modificación asíncrona. Gracias por la explicación, ahora veo lo que dice ese pasaje de jerga legal. Punto interesante que el_Atomic
tiene que estar libre de bloqueo. Dado que es un controlador de señales en el mismo subproceso, crearía un punto muerto potencial para que el controlador de señales intente adquirir un bloqueo que a veces tiene el subproceso.– Peter Cordes
9 sep 2016 a las 19:19
Ciertos tipos pueden requerir múltiples instrucciones para leer/escribir. int
type siempre se lee/escribe atómicamente.
Tipo de datos: sig_atomic_t
Este es un tipo de datos entero. A los objetos de este tipo siempre se accede de forma atómica.
En la práctica, puede suponer que int y otros tipos de enteros no más largos que int son atómicos. También puede suponer que los tipos de punteros son atómicos; eso es muy conveniente. Ambos son ciertos en todas las máquinas compatibles con la biblioteca GNU C y en todos los sistemas POSIX que conocemos.
-
Es generalmente el caso de que
int
siempre se lee y escribe atómicamente. El estándar C no garantiza esto específicamente. La implementación, definiendosig_atomic_t
comoint
promete que ese es el caso para esa implementación. No debe asumir que es cierto para todas las implementaciones.–Keith Thompson
07/03/2012 a las 18:40
-
una mas actual referencia. Solo para aclarar, ¿esto solo se aplica a la biblioteca GNU C? ¿Con o sin GCC? Nunca he oído hablar de un tipo simple que tenga acceso atómico en el estándar C (excluyendo los métodos atómicos normales y los mecanismos de bloqueo).
– ioan
7 de marzo de 2012 a las 18:42
-
@Ioan C99 no tiene un modelo de concurrencia, por lo que lo que significa “atómico” es algo muy débil en comparación con lo que probablemente esté pensando. Mira mi respuesta.
– zwol
7 de marzo de 2012 a las 19:28
@chrisaycock: C? ¿No se aplicaría esto a cualquier idioma con acceso a
sig_atomic_t
variables? Podría haber usado con la misma facilidadg++
.– smcdow
7 de marzo de 2012 a las 18:55
los
sig_atomic_t
type es en realidad parte de la especificación C. También se encuentra en la especificación C++ (como la mayoría de las cosas), pero es más probable que obtenga buenas respuestas con una etiqueta C.-Dietrich Epp
07/03/2012 a las 19:31
C no garantiza eso. Las CPU específicas tienen garantías específicas para la atomicidad de ciertos tipos. En particular, las CPU modernas utilizadas en los sistemas de escritorio tienden a garantizar la atomicidad al menos para alineados.
int
s (es decir, datos del tamaño de una palabra de plataforma). Este no es necesariamente el caso de las CPU más antiguas o de las CPU utilizadas en sistemas integrados.– ninjalj
7 de marzo de 2012 a las 19:59