2008-09-10 12 views
69

Tengo dos hilos, uno que actualiza un int y otro que lo está leyendo. Este es un valor estadístico donde el orden de las lecturas y escrituras es irrelevante.¿Las lecturas y escrituras de C++ de un Atomic interno?

Mi pregunta es, ¿necesito sincronizar el acceso a este valor de varios bytes de todos modos? O, dicho de otra manera, puede que parte de la escritura se complete y se interrumpa, y luego la lectura ocurre.

Por ejemplo, piense en un valor = 0x0000FFFF que obtiene un valor incrementado de 0x00010000.

¿Hay algún momento en el que el valor se vea como 0x0001FFFF y me preocupe? Sin duda, cuanto más grande sea el tipo, más posible es que algo así suceda.

Siempre sincronicé este tipo de accesos, pero me di cuenta de lo que piensa la comunidad.

+4

serio? No me importaría lo que pensara la comunidad. Me importaría cuáles son los hechos :) – sehe

+1

Interesante leer sobre el tema: http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Herb-Sutter-atomic-Weapons-1- of-2 – ereOn

+0

Específicamente para '=': http://stackoverflow.com/questions/8290768/is-assignment-operator-atomic –

Respuesta

39

Al principio uno podría pensar que las lecturas y escrituras del tamaño de la máquina nativa son atómicas, pero hay una serie de problemas para tratar, incluida la coherencia de caché entre los procesadores/núcleos. Utilice operaciones atómicas como Interbloqueado * en Windows y su equivalente en Linux. C++ 0x tendrá una plantilla "atómica" para envolverlos en una interfaz agradable y multiplataforma. Por ahora, si está utilizando una capa de abstracción de plataforma, puede proporcionar estas funciones. ACE, ver la plantilla de clase ACE_Atomic_Op.

+0

El documento de ACE_Atomic_Op se ha movido - ahora se puede encontrar en http://www.dre.vanderbilt.edu/~schmidt/DOC_ROOT/ACE/ace/Atomic_Op.inl – Byron

+0

he actualizado el enlace –

0

No, no lo son (o al menos no puede suponer que lo son). Habiendo dicho eso, hay algunos trucos para hacer esto atómicamente, pero típicamente no son portátiles (ver Compare-and-swap).

8

Sí, necesita sincronizar accesos. En C++ 0x será una carrera de datos y un comportamiento indefinido. Con los hilos POSIX ya es un comportamiento indefinido.

En la práctica, es posible que obtenga valores incorrectos si el tipo de datos es más grande que el tamaño de la palabra nativa. Además, es posible que otro subproceso no vea el valor escrito debido a las optimizaciones que mueven la lectura o la escritura.

3

Debe sincronizar, pero en ciertas arquitecturas hay formas eficientes de hacerlo.

Lo mejor es usar subrutinas (quizás enmascaradas detrás de las macros) para que pueda reemplazar de forma condicional las implementaciones con plataformas específicas.

El kernel de Linux ya tiene algo de este código.

9

SI está leyendo/escribiendo el valor de 4 bytes Y está alineado DWORD en la memoria Y se está ejecutando en la arquitectura I32, ENTONCES las lecturas y escrituras son atómicas.

+2

¿Dónde está indicado esto en los manuales del desarrollador del software de arquitectura Intel? –

+1

@DanielTrebbien: quizás vea http: // stackoverflow.com/questions/5002046/atomicity-in-c-myth-or-reality – sehe

57

Muchacho, qué pregunta. La respuesta a lo que es:

Sí, no, hmmm, bueno, depende

Todo se reduce a la arquitectura del sistema. En un IA32, una dirección correctamente alineada será una operación atómica. Las escrituras desalineadas pueden ser atómicas, depende del sistema de almacenamiento en caché en uso. Si la memoria se encuentra dentro de una sola línea de caché L1, entonces es atómica; de lo contrario, no lo es. El ancho del bus entre la CPU y la RAM puede afectar la naturaleza atómica: una escritura de 16 bits alineada correctamente en un 8086 era atómica, mientras que la misma escritura en un 8088 no era porque el 8088 solo tenía un bus de 8 bits mientras que el 8086 tenía un Bus de 16 bits

Además, si está utilizando C/C++, no olvide marcar el valor compartido como volátil; de lo contrario, el optimizador considerará que la variable nunca se actualiza en uno de sus hilos.

+14

La palabra clave volátil no es útil en programas multiproceso http://stackoverflow.com/questions/2484980/why-is-volatile-not-considered-useful -en-multiproceso-c-o-programación-c –

+3

@IngeHenriksen: no me convence ese enlace. – Skizz

0

Estoy de acuerdo con muchos y especialmente Jason. En Windows, uno probablemente usaría InterlockedAdd y sus amigos.

1

Para hacer eco de lo que todos decían en el piso de arriba, el lenguaje pre-C++ 0x no puede garantizar nada sobre el acceso a memoria compartida desde varios subprocesos. Cualquier garantía dependería del compilador.

0

asside de la cuestión de caché se mencionó anteriormente ...

Si transfiere el código para un procesador con un tamaño más pequeño registro no será atómica más.

OMI, problemas de enhebrado son demasiado espinosos para arriesgarlo.

3

En Windows, Interbloqueado *** Cambiar *** Agregar está garantizado para ser atómico.

-1

La única forma portátil es usar el tipo sig_atomic_t definido en el encabezado signal.h para su compilador. En la mayoría de las implementaciones C y C++, eso es un int. Luego declare su variable como "volátil sig_atomic_t".

+0

volátil no hace qué crees que lo hace http://stackoverflow.com/questions/2484980/why-is-volatile-not-considered-useful-in-multithreaded-c-or-c-programming –

0

permite echar este ejemplo

int x; 
x++; 
x=x+5; 

La primera declaración se supone que es atómica, ya que se traduce en una única directiva de ensamblado INC que toma un solo ciclo de la CPU. Sin embargo, la segunda asignación requiere varias operaciones, por lo que claramente no es una operación atómica.

Otro por ejemplo,

x=5; 

vez más, usted tiene que desmontar el código para ver qué es exactamente lo que ocurre aquí.

+0

Pero el compilador podría optimizarlo en 'x + = 6'. –

0

tc, Creo que en el momento en que use una constante (como 6), la instrucción no se completará en un ciclo de máquina. Intente ver el conjunto de instrucciones de x + = 6 en comparación con x ++

0

Algunas personas piensan que ++ c es atómico, pero tiene un ojo en el conjunto generado. Por ejemplo, con 'gcc -S':

movl cpt.1586(%rip), %eax 
addl $1, %eax 
movl %eax, cpt.1586(%rip) 

para incrementar un int, el compilador primero cargarlo en un registro, y lo almacena de nuevo en la memoria. Esto no es atómico.

+1

Esto no es un problema si solo un hilo está escribiendo en la variable, ya que no hay rasgado. –

1

Definitivamente NO! esa respuesta de nuestra máxima autoridad de C++, M. Boost:
Operations on "ordinary" variables are not guaranteed to be atomic.

+0

ese enlace solo dice que la operación 'aritmética' que consiste en una secuencia de lectura-actualización-escritura en variables 'ordinarias' no es atómica, no si' lectura' o 'escritura' en variables 'ordinarias' son atómicas o no. – D3Hunter

Cuestiones relacionadas