2010-05-23 18 views
9

Una pregunta rápida que me he estado preguntando por algún tiempo; ¿La CPU asigna valores atómicamente, o, es bit por bit (por ejemplo, un entero de 32 bits).
Si es poco a poco, ¿podría otro subproceso que accede a esta ubicación exacta obtener una "parte" del valor que se le asignará?¿Una CPU asigna un valor atómico a la memoria?

Piensa en esto:
Tengo dos hilos y una variable "unsigned int" compartida (llámala "g_uiVal").
Ambos subprocesos en bucle.
Activado está imprimiendo "g_uiVal" con printf ("% u \ n", g_uiVal).
El segundo solo aumenta este número.
¿El hilo de impresión alguna vez imprimirá algo que no sea totalmente o parte del valor de "g_uiVal"?

En código:

unsigned int g_uiVal; 

void thread_writer() 
{ 
g_uiVal++; 
} 
void thread_reader() 
{ 
while(1) 
    printf("%u\n", g_uiVal); 
} 

Respuesta

5

Depende del ancho del bus de la CPU y la memoria. En un contexto de PC, con algo más que una CPU realmente antigua, los accesos de hasta 32 bits son atómicos; Los accesos de 64 bits pueden o no ser. En el espacio integrado, muchas CPU (¿la mayoría?) Tienen 32 bits de ancho y no hay nada más amplio, por lo que se garantiza que su int64_t no sea atómico.

+0

¿Es posible acceder a los valores de 32 bits que cruzan las líneas de caché en estos días? –

+0

@Lasse: muchos procesadores de escritorio modernos permiten lecturas y escrituras desalineadas, pero con una importante penalización de rendimiento. Las CPU antiguas o más pequeñas (por ejemplo, dispositivos integrados) tienden a no hacerlo. Durante algún tiempo, esto se dividió entre procesadores CISC (tendidos para admitir lecturas y escrituras no alineadas) y procesadores RISC (no lo hicieron), pero las distinciones se difuminan aquí. – leander

+0

Los microcontroladores de 8, 16 y 32 bits son comunes. En un AVR (con cargas de 8 bits y tiendas) es posible tener otro ISR (rutina de servicio de interrupción) u otro hilo (si está ejecutando un sistema operativo multitarea elegible) escribir parte de la variable (o simplemente leer parte del cambiar que hizo el hilo anterior). – nategoose

3

Creo que la única respuesta correcta es "depende". En lo que puedes preguntar?

Bueno para principiantes qué CPU. Pero también algunas CPU son atómicas para escribir valores de ancho de palabra, pero solo cuando están alineadas. Realmente no es algo que pueda garantizar a un nivel de lenguaje C.

Muchos compiladores ofrecen "intrínsecos" para emitir operaciones atómicas correctas. Estas son extensiones que actúan como funciones, pero emiten el código correcto para su arquitectura de destino para obtener las operaciones atómicas necesarias. Por ejemplo: http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html

0

Para agregar a lo que se ha dicho hasta ahora, otra posible preocupación es el almacenamiento en caché. Las CPU tienden a funcionar con la caché de memoria local (al morir) que puede o no volverse a enjuagar inmediatamente a la memoria principal. Si la caja tiene más de una CPU, es posible que otra CPU no vea los cambios durante un tiempo después de que la CPU modificadora los haya realizado, a menos que haya algún comando de sincronización que informe a todas las CPU que deben sincronizar sus cachés en el dado. Como se puede imaginar, dicha sincronización puede ralentizar considerablemente el procesamiento.

+0

Pero en este caso, dado que no hay sincronización entre el consumidor y el productor, realmente no cambia el comportamiento. Claro, el consumidor podría leer un valor anterior, pero no sería posible saber si se debió a cachés en sincronía no sincronizados o simplemente a la programación. Lo que quiero decir es que el consumidor nunca leería un valor parcialmente escrito debido a cachés no sincronizados –

+0

Todo depende de lo que se espera. Si la intención es producir valores únicos, ¿este problema puede presentar duplicados – mfeingold

0

No olvide que el compilador asume un solo hilo al optimizar, y todo esto podría desaparecer.

+0

a pesar de que es una variable global que está claramente en uso en otras funciones? Dudo que ningún compilador sea * que * grosero :) –

+0

@Isak Savo: variable global no volátil estática (no externa)? ¿Seguro Por qué no? Marque todas las variables utilizadas para el control de concurrencia como volátiles, esto evita las optimizaciones del compilador relacionadas con estas variables. – liori

+0

@liori: Pero incluso en una única aplicación con hebras, es un código perfectamente válido.Aparte de la mala arquitectura, no tiene nada de malo hacer que una función modifique las variables globales sin usar el resultado. –

1

Ha dicho "poco a poco" en su pregunta. No creo que ninguna arquitectura haga operaciones de a poco a la vez, excepto con algunos buses de protocolo de serie especializados. Las lecturas/escrituras de memoria estándar se realizan con 8, 16, 32 o 64 bits de granularidad. Entonces, es POSIBLE que la operación en su ejemplo sea atómica.

Sin embargo, la respuesta depende en gran medida de la plataforma.

  • Depende de las capacidades de la CPU. ¿Puede el hardware realizar una operación atómica de 32 bits ? Aquí hay una sugerencia: Si la variable que está trabajando es más grande que el tamaño de registro nativo (por ejemplo, 64-bit int en un sistema de 32 bits), es definitivamente NO atómico.
  • Depende de cómo el compilador genera el código de máquina. Podría haber convertido el acceso variable de 32 bits en lecturas de memoria de 4 bits de 8 bits.
  • Se vuelve complicado si la dirección de la que está accediendo no está alineada a través de la palabra natural de la máquina boundary. Puede presionar un error de caché o un error de página.

Es MUY POSIBLE que vea un valor corrupto o inesperado utilizando el ejemplo del código que ha publicado.

Su plataforma probablemente proporciona algún método para realizar operaciones atómicas. En el caso de una plataforma de Windows, es a través del Interlocked functions. En el caso de Linux/Unix, mira el atomic_t type.

0

POSIX define el tipo especial sig_atomic_t que garantiza que las escrituras son atómicas con respecto a las señales, lo que lo hará también atómico desde el punto de vista de otros hilos como desee. No definen específicamente un tipo de hilo cruzado atómico como este, ya que se espera que la comunicación de subprocesos esté mediada por mutex u otras primitivas de sincronización.

0

Considerando los microprocesadores modernos (y los microcontroladores que ignoran), la asignación de 32 bits es atómica, no bit por bit.

Sin embargo, ahora completamente fuera del tema de su pregunta ... el hilo de impresión podría imprimir algo que no se espera debido a la falta de sincronización en este ejemplo, por supuesto, debido a la reordenación de instrucciones y múltiples núcleos cada uno con su propia copia de g_uiVal en sus cachés.

Cuestiones relacionadas