tipos significado programa lenguaje entrada ejemplos datos caracteristicas c++ multithreading synchronization mutex

significado - Hilo de C++, datos compartidos



programa en c++ (10)

Chris Jester-Young señaló que:

Esto solo funciona bajo el modelo de memoria de Java 1.5 +. El estándar de C ++ no aborda el enhebrado y volátil no garantiza la coherencia de memoria entre los procesadores. Necesitas una barrera de memoria para esto

Siendo así, la única respuesta verdadera es implementar un sistema de sincronización, ¿verdad?

Tengo una aplicación donde se están ejecutando 2 subprocesos ... ¿Hay alguna certeza de que cuando cambio una variable global de un subproceso, el otro notará este cambio? No tengo implementado ningún sistema de sincronización mutua o de sincronización ... pero este código debería funcionar todo el tiempo (imagine un bool global llamado dataUpdated ):

Tema 1:

while(1) { if (dataUpdated) updateScreen(); doSomethingElse(); }

Tema 2:

while(1) { if (doSomething()) dataUpdated = TRUE; }

¿Un compilador como gcc optimiza este código de una manera que no verifica el valor global, solo considerando su valor en tiempo de compilación (porque nunca se cambia en el mismo paquete)?

PD: Siendo esto para una aplicación similar a un juego, realmente no importa si habrá una lectura mientras se escribe el valor ... todo lo que importa es que el cambio sea notado por el otro hilo.


No, no es seguro. Si declara que la variable es volátil, se supone que el compilador genera código que siempre carga la variable de la memoria en una lectura.


Sí. No, quizás.

En primer lugar, como otros lo han mencionado, debes hacer que dataUpdate sea volátil; de lo contrario, el compilador puede levantar libremente la lectura desde el bucle (dependiendo de si puede o no ver que DoSomethingElse no lo toca).

En segundo lugar, dependiendo de su procesador y las necesidades de pedido, es posible que necesite barreras de memoria. volátil es suficiente para garantizar que el otro procesador verá el cambio con el tiempo, pero no lo suficiente para garantizar que los cambios se verán en el orden en que se realizaron. Tu ejemplo solo tiene una bandera, por lo que realmente no muestra este fenómeno. Si necesita y usa barreras de memoria, ya no debería necesitar volátiles

Volatile considerado dañino y Linux Kernel Memory Barriers son buenos antecedentes sobre los problemas subyacentes; Realmente no conozco nada similar escrito específicamente para enhebrar. Afortunadamente, los hilos no plantean estas preocupaciones casi tan a menudo como los periféricos de hardware, aunque el tipo de caso que describes (un indicador que indica que se completó, con otros datos que se presume válidos si se establece el indicador) es exactamente el tipo de ordenamiento materias ...


Si el alcance es correcto ("externo", global, etc.), se notará el cambio. La pregunta es cuando? ¿Y en qué orden?

El problema es que el compilador puede y con frecuencia volverá a ordenar su lógica para llenar todas sus interconexiones simultáneas como una optimización del rendimiento.

Realmente no se muestra en su ejemplo específico porque no hay otras instrucciones en torno a su asignación, pero imagine las funciones declaradas después de que su bool assign se ejecute antes de la asignación.

Verifique el peligro del oleoducto en la wikipedia o busque en google "reordenamiento de la instrucción del compilador"


Su solución usará 100% de CPU, entre otros problemas. Google para "variable de condición".


Use la palabra clave volátil para indicar al compilador que el valor puede cambiar en cualquier momento.

volatile int myInteger;


Use la palabra clave volátil para indicar al compilador que el valor puede cambiar en cualquier momento.

volatile int myInteger;

Lo anterior garantizará que cualquier acceso a la variable será hacia y desde la memoria sin optimizaciones específicas y, como resultado, todos los hilos que se ejecutan en el mismo procesador "verán" cambios en la variable con la misma semántica que el código.

Chris Jester-Young señaló que la preocupación por la coherencia de dicho cambio de valor variable puede surgir en un sistema multiprocesador. Esto es una consideración y depende de la plataforma.

En realidad, realmente hay dos consideraciones para pensar en relación con la plataforma. Son coherencia y atomicidad de las transacciones de memoria.

La atomicidad es en realidad una consideración tanto para plataformas de procesador único como multiprocesador. El problema surge porque la variable es probablemente de varios bytes en la naturaleza y la pregunta es si un hilo podría ver una actualización parcial del valor o no. es decir: algunos bytes cambiados, cambio de contexto, valor no válido leído al interrumpir el hilo. Para una sola variable que está en el tamaño de la palabra de la máquina natural o más pequeño y naturalmente alineado no debería ser una preocupación. Específicamente, un tipo int siempre debería estar bien a este respecto, siempre que esté alineado, que debería ser el caso predeterminado para el compilador.

En relación con la coherencia, esta es una preocupación potencial en un sistema multiprocesador. La pregunta es si el sistema implementa la coherencia total del caché o no entre los procesadores. Si se implementa, esto generalmente se hace con el protocolo MESI en hardware. La pregunta no indicaba plataformas, pero tanto las plataformas Intel x86 como las plataformas PowerPC son coherentes entre los procesadores para regiones de datos de programas normalmente mapeados. Por lo tanto, este tipo de problema no debería ser una preocupación para los accesos de memoria de datos ordinarios entre subprocesos, incluso si hay múltiples procesadores.

El último problema relativo a la atomicidad que surge es específico de la atomicidad lectura-modificación-escritura. Es decir, cómo se garantiza que si se lee un valor actualizado en el valor y el escrito, que esto ocurra atómicamente, incluso en todos los procesadores si hay más de uno. Por lo tanto, para que esto funcione sin objetos de sincronización específicos, se requeriría que todos los subprocesos potenciales que acceden a la variable sean lectores ÚNICAMENTE pero se espera que solo un hilo pueda ser escritor al mismo tiempo. Si este no es el caso, entonces necesita un objeto de sincronización disponible para poder garantizar acciones atómicas en las acciones de lectura, modificación y escritura de la variable.


Aquí hay un ejemplo que usa variables de condición de impulso:

bool _updated=false; boost::mutex _access; boost::condition _condition; bool updated() { return _updated; } void thread1() { boost::mutex::scoped_lock lock(_access); while (true) { boost::xtime xt; boost::xtime_get(&xt, boost::TIME_UTC); // note that the second parameter to timed_wait is a predicate function that is called - not the address of a variable to check if (_condition.timed_wait(lock, &updated, xt)) updateScreen(); doSomethingElse(); } } void thread2() { while(true) { if (doSomething()) _updated=true; } }


Usa un candado Siempre use siempre un candado para acceder a los datos compartidos. Marcar la variable como volátil evitará que el compilador optimice la lectura de la memoria, pero no evitará otros problemas como el reordenamiento de la memoria . Sin un bloqueo no hay garantía de que la memoria escribe en doSomething () será visible en la función updateScreen ().

La única otra manera segura es usar una valla de memoria , explícita o implícitamente usando una función enclavada * por ejemplo.


Como otros han dicho, la palabra clave volatile es tu amigo. :-)

Lo más probable es que descubra que su código funcionaría cuando tuviera desactivadas todas las opciones de optimización en gcc. En este caso (creo) trata todo como volátil y, como resultado, se accede a la variable en memoria para cada operación.

Con cualquier tipo de optimización activada, el compilador intentará usar una copia local en un registro. Dependiendo de sus funciones, esto puede significar que solo ve el cambio en la variable intermitentemente o, en el peor, nunca.

El uso de la palabra clave volatile indica al compilador que el contenido de esta variable puede cambiar en cualquier momento y que no debe usar una copia en caché local.

Con todo lo dicho, puede encontrar mejores resultados (como los alude Jeff ) mediante el uso de un semáforo o una variable de condición.

Esta es una introducción razonable al tema.