2010-03-18 5 views
30

¿Los operadores de "modificación" son +=, |=, &= etc. atomic?¿Son + =, | =, & = etc atómicos?

++ es atómica (si realiza x++; en dos temas diferentes "simultáneamente", siempre se va a terminar con x aumentado en un 2, a diferencia de x=x+1 con la optimización de apagado.)

Lo que me pregunto es si variable |= constant, y los gustos son thread-safe o tengo que protegerlos con un mutex?

(... ¿o no dependiendo de la CPU? En este caso, ¿cómo es en ARM?)

+1

¿Qué ARM? La arquitectura v6 (ARM10) y más adelante puede proporcionar operaciones atómicas, si el compilador lo admite o usted desenrolla su propio ensamblaje. Las arquitecturas anteriores no pueden. –

+0

gcc tiene operaciones atómicas integradas: http://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Atomic-Builtins.html#Atomic-Builtins; tenga en cuenta: "No todas las operaciones son compatibles con todos los procesadores de destino" – Christoph

+0

hay una API de Windows para el acceso variable interconectado: http://msdn.microsoft.com/en-us/library/ms684122%28v=VS.85%29.aspx –

Respuesta

72

Usted está equivocado. No hay garantía de que ++ sea atómico y tampoco lo es para los operadores de asignación compuesta, o de hecho para cualquier operación de C++.

+3

Lo que significa que esto es específico de la CPU. En las arquitecturas de un solo núcleo que permiten 'inc [dirección]', esto es definitivamente atómico. –

+1

Al menos no hasta C++ 0x: "Esta cláusula describe componentes para el acceso atómico de grano fino. Este acceso se proporciona a través de operaciones en objetos atómicos". [29.1/1 en el borrador n3035]. –

+24

@SF No, no lo es. Es específico del compilador.El hecho de que una arquitectura de CPU tenga una instrucción no significa que el compilador la usará de la manera que usted cree que debería hacerlo, si es que la usa. –

6

Para que el cambio en el valor sea visible entre los núcleos, a + = (por ejemplo) tendría que cargar el valor, agregar el incremento y luego almacenarlo. Esto significa que la operación no será atómica.

Para garantizar la atomicidad, debe colocar un bloqueo adecuado alrededor de la operación.

2

++ puede ser atómico en su compilador/plataforma, pero en las especificaciones de C++ no está definido como atómico.

Si desea asegurarse de modificar un valor de forma atómica, debe utilizar los métodos adecuados, como Interbloqueado * en Windows.

Lo mismo para todas las otras rutinas. Si desea operaciones atómicas, debe usar las llamadas apropiadas, no las estándar.

2

No operador en C o C++ se garantiza que es atómico. Podrían estar en tu plataforma, pero no lo sabrás con certeza. Normalmente, la única operación que es atómica es la instrucción Test and Set, que generalmente está disponible en la mayoría de las CPU modernas de alguna forma como base para implementar semáforos.

9

x++ a menudo se implementa en 3 instrucciones: Lea X en un registro, increméntelo y escríbalo nuevamente en la memoria.

Su hilo puede ser anulado entre cualquiera de esos.

+1

En algunos procesadores, incluso las instrucciones individuales pueden ser no atómicas. –

0

Vale la pena mencionar que estos operadores pueden estar sobrecargados, por lo que ciertamente no puede haber una garantía general de que sean atómicos para todas las clases.

+1

No se pueden sobrecargar para enteros, de lo que creo que se trata la pregunta. –

+0

De acuerdo, pero no dice eso, por lo que pensé que valía la pena mencionarlo. – Oddthinking

0

Incluso si ++ es una operación atómica, que no implica que dos hilos haciendo ++x dará como resultado x siendo exactamente dos más altos. Tienes que sincronizar los hilos de alguna manera, o de lo contrario no necesariamente verán los cambios de los demás.

0

usted tiene que proteger su variable, con un mutex por ejemplo

2

Es a la vez compilador y dependiente de la CPU. Algunos conjuntos de instrucciones proporcionan instrucciones atómicas para estos (en unidades de tamaño de máquina).

Sin embargo, no hay ninguna garantía de que el compilador use esas instrucciones y no optimice su código de una manera que no sea segura para las hebras. Debe escribir una rutina en ensamblaje o usar una técnica específica del compilador (como instrinsics) que proporcione atomicidad (o use una biblioteca que use una de esas técnicas).


Específicamente en ARM: La TRG/ADD/Y instrucciones a dos operandos y coloca el resultado en un registro. Cualquiera de los dos operandos puede ser el mismo registro que el registro de resultados, por lo que pueden utilizarse como atomic | =, + =, & =.

Por supuesto, el resultado se coloca en un registro y el primer operando también debe provenir de un registro, por lo que deberá asegurarse de que las cargas de registro se realicen atómicamente.

1

Un duplicar fue dirigido aquí, y esto necesita una actualización. El “nuevo” lenguaje C11 permite un atributo atómica que admite que:

_Atomic int a; 
... 
a += 3 

pueden ser compilados en un bucle sin límites (atómica). Gracias por la gente de estándares de regalos, realmente desearía que no lo hubieras hecho.

1: en algunas arquitecturas, las operaciones atómicas solo son posibles en la memoria que admite ciertos protocolos de acceso. ARMv7, MIPS, por ejemplo, encender la secuencia en:

do { 
    x = LoadLinked(a) + 3; 
} while !StoreConditional(x, &a); 

pero LoadLinked/StoreConditional no está definido para algunos tipos de memoria/caché. Disfruta de depurar eso.

2: relacionado es falsa compartir que es un artefacto de LoadLinked, StoreConditional operando sobre líneas de caché no sub-bloques (por ejemplo, 32, 64, 256 bytes.). Entonces: _Atomic int a [4]; podría requerir 4 * tamaño de línea de caché (por lo tanto 1024 bytes) para permitir operaciones atómicas simultáneas en un [n] y un [n + 1], porque 4 CPU podrían estar luchando para actualizar un [0..3], pero nunca subsiguiente.

Esperemos que la próxima norma reconozca la falla inherente de la decoración de atributos, y restituya c89 como el estándar de C correcto.

Cuestiones relacionadas