2010-02-26 14 views
6

Estoy escribiendo una aplicación C++.C++ variables de subprocesamiento volátil

Tengo una variable de clase en la que está escribiendo más de un hilo.

En C++, todo lo que se puede modificar sin que el compilador se "dé cuenta" de que se está cambiando debe marcarse como volátil ¿no? Entonces, si mi código es multihebra, y un hilo puede escribir en una var mientras otro lee de él, ¿necesito marcar el var volaltile?

[I no tienen una condición de carrera ya que estoy confiando en las escrituras a ser enteros atómica]

Gracias!

+9

¿Qué te hace pensar que las escrituras serán atómicas? – bmargulies

+4

No soy un experto en multihilo, pero siempre implementaría el bloqueo de cualquier recurso compartido ... –

+0

He hecho este tipo de cosas en un procesador PowerPC single-core integrado y funciona de manera confiable. Mejor no hacer ninguna lectura-modificación-escritura (como '++ sharedInt') si es posible que dos hilos tengan acceso de escritura. (En realidad, si dos hilos pueden escribir, probablemente solo sea útil si limita ** cuando ** pueden escribir. Por ejemplo, el hilo A puede cambiar 'sharedInt' de 0 a 1, mientras que el hilo B puede cambiarlo de 1 a 0.) – Dan

Respuesta

3

volátil instruir al compilador para que no se optimice con la "intuición" de un valor variable o uso, ya que podría optimizarse "desde el exterior".

volátil no proporcionará ninguna sincronización, sin embargo, su suposición de que las escrituras en atomic son prácticamente realistas.

Supongo que necesitaríamos ver algún uso para saber si es necesario volátil en su caso (o controlar el comportamiento de su programa) o más importante si ve algún tipo de sincronización.

+0

Eso NO es cierto, cuando construye aplicaciones/algoritmos HPC, por lo general, conoce muy bien la arquitectura con la que va a trabajar. Y así no agregará un bloqueo inútil, si no lo necesita. – Ben

+0

Bueno hum, mi punto de vista al menos. – Ben

+0

Siempre pensé que escribir un int era una operación atómica (al menos en una CPU x86). ¿Tienes alguna buena documentación sobre operaciones atómicas? –

0

Sin bloqueos, es posible que el fabricante o el procesador realicen nuevas 'imposibles' reordenaciones. Y no hay garantía de que las escrituras en ints sean atómicas.

Sería mejor utilizar un bloqueo adecuado.

13

C++ no tiene aún ninguna provisión para multihilo. En la práctica, volátil no hace lo que usted quiere decir (se ha diseñado para hardware con memoria de acceso y, aunque los dos problemas son similares, son lo suficientemente diferentes como para que volátiles no hagan lo correcto; tenga en cuenta que se ha utilizado volátil en otros lenguaje para usos en contextos mt).

Así que si quiere escribir un objeto en un hilo y leerlo en otro, tendrá que usar las características de sincronización que su implementación necesita cuando las necesita. Por el que yo sé, el papel volátil no desempeña ningún papel en eso.

FYI, el siguiente estándar tendrá en cuenta MT, y volátil no desempeñará ningún papel en eso. Entonces eso no cambiará Simplemente tendrá condiciones definidas estándar en las que se necesita sincronización y una forma estándar definida de lograrlas.

+0

"En la práctica, volátil no hace lo que quieres decir". ¿¿Qué?? Volatile está diseñado para evitar optimizaciones del compilador en una variable. Es sumamente, muy recomendable para la programación multiproceso. No intente programación multiproceso sin volátil. Su programa puede funcionar bien durante años y de repente sale de la nada. –

+0

@annoying_squid, ver http://stackoverflow.com/a/2485177/136208. A partir de C++ 11, 'std :: atomic <>' es probablemente la manera de obtener lo que usted cree que sería volátil. – AProgrammer

-4

Volatile resolverá su problema, es decir. garantizará la coherencia entre todos los cachés del sistema. Sin embargo, será ineficaz ya que actualizará la variable en memoria para cada acceso R o W. Puede considerar utilizar una barrera de memoria, solo cuando sea necesario. Si está trabajando con o gcc/ICC tienen un aspecto de sincronización empotrados: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

EDITAR (en su mayoría sobre el comentario PM100): entiendo que mis creencias no son una referencia, de manera que he encontrado algo citar :)

La palabra clave volátil se diseñó para evitar las optimizaciones del compilador que pueden hacer que el código sea incorrecto en presencia de ciertos eventos asincrónicos.Por ejemplo,Si se declara una variable primitiva tan volátil, el compilador no está permitido para almacenar en caché en un registro

De Dr Dobb's

Más interesante:

campos volátiles son linealizable. Leer un campo volátil es como adquirir un candado; la memoria de trabajo se invalida y el valor actual del campo volátil se vuelve a leer de la memoria. Escribir un campo volátil es como soltar un candado: el campo volátil se escribe de inmediato en la memoria. (esto es todo acerca de la consistencia, no se trata de atomicidad)

de El arte de la programación de multiprocesador, Maurice Herlihy & Nir Shavit

bloqueo contiene código de sincronización de memoria, si no de bloqueo, debe hacer algo y usar palabras clave volátiles es probablemente lo más simple que puede hacer (incluso si fue diseñado para dispositivos externos con memoria atada al espacio de direcciones, no es el punto aquí)

+0

¿Por qué esta respuesta está downvoted? – anon

+1

porque está mal. volátil no tiene nada que ver con los cachés de memoria. – pm100

+0

@ pm100, No fue diseñado para esto, estoy de acuerdo, pero tiene que ver con los cachés, ver mi edición, por favor. – Ben

4

Sí, el mínimo absoluto es 'volátil' Necesitaré Asegura que el generador de códigos no genere código que almacene la variable en un registro y siempre realice lecturas y escrituras desde/hacia la memoria. La mayoría de los generadores de código pueden proporcionar garantías de atomicidad en variables que tienen el mismo tamaño que la palabra de la CPU nativa, se asegurarán de que la dirección de la memoria esté alineada para que la variable no pueda abarcar un límite de la línea de caché.

Sin embargo, ese no es un contrato muy fuerte en las CPU modernas multi-core. Volatile does not promete que otro subproceso que se ejecuta en otro núcleo puede ver actualizaciones de la variable. Eso requiere una barrera de memoria, generalmente una instrucción que vacía el caché de la CPU. Si no proporciona una barrera, el hilo seguirá funcionando hasta que se produzca dicha descarga de forma natural. Eso eventualmente sucederá, el programador de hilos está obligado a proporcionar uno. Eso puede tomar milisegundos.

Una vez que se ha ocupado de detalles como este, eventualmente habrá reinventado una variable de condición (evento aka) que probablemente no sea más rápida que la proporcionada por una biblioteca de subprocesos. O bien probado. No inventes el tuyo, el enhebrado es lo suficientemente difícil para hacerlo bien, no necesitas el FUD para no estar seguro de que los primitivos básicos son sólidos.

+2

Volátil no es el mínimo absoluto. Está muy por debajo del mínimo. El mínimo también debería evitar el reordenamiento de lectura/escritura alrededor de la variable compartida. – jalf

+0

@jalf - ¿Cuántas graduaciones por debajo del "mínimo absoluto" consideras? –

+0

Solo uno: "debajo";) – jalf

1

Creo que volatile solo se aplica realmente a la lectura, especialmente la lectura de registros de E/S mapeados en memoria.

Se puede utilizar para indicar al compilador no asumir que una vez que se ha leído desde una ubicación de memoria que el valor no cambiará:

while (*p) 
{ 
    // ... 
} 

En el código anterior, si *p no se escribe dentro del bucle, el compilador puede decidir mover la lectura fuera del bucle, de la misma familia:

cached_p=*p 
while (cached_p) 
{ 
    // ... 
} 

Si p es un puntero a un puerto de E/S mapeada en memoria, le gustaría que la primera versión en la que el el puerto se verifica antes de ingresar el bucle y tiempo

Si p es un puntero a la memoria en una aplicación multiproceso, todavía no se garantiza que las escrituras sean atómicas.

+6

No se trata solo de leer: "para (i = 0; i <10; ++ i) {j = i;} se puede reemplazar por j = 10; cuando j no es volátil. – stefaanv