variable usar tipo operaciones definir dato como booleano booleanas booleana bool c++ multithreading locking boolean monitor

c++ - usar - ¿Está bien leer un indicador booleano compartido sin bloquearlo cuando otro hilo puede establecerlo(como máximo una vez)?



variable de tipo booleano en c (4)

Me gustaría que mi hilo se cierre con mayor gracia, así que estoy tratando de implementar un mecanismo de señalización simple. No creo que quiera un hilo totalmente orientado a eventos, así que tengo un trabajador con un método para detenerlo de forma elegante usando un Monitor sección crítica (creo que es equivalente a un lock C #):

DrawingThread.h

class DrawingThread { bool stopRequested; Runtime::Monitor CSMonitor; CPInfo *pPInfo; //More.. }

DrawingThread.cpp

void DrawingThread::Run() { if (!stopRequested) //Time consuming call#1 if (!stopRequested) { CSMonitor.Enter(); pPInfo = new CPInfo(/**/); //Not time consuming but pPInfo must either be null or constructed. CSMonitor.Exit(); } if (!stopRequested) { pPInfo->foobar(/**/);//Time consuming and can be signalled } if (!stopRequested) { //One more optional but time consuming call. } } void DrawingThread::RequestStop() { CSMonitor.Enter(); stopRequested = true; if (pPInfo) pPInfo->RequestStop(); CSMonitor.Exit(); }

Entiendo (al menos en Windows) Monitor / lock s son las primitivas de sincronización de subprocesos menos costosas, pero estoy dispuesto a evitar el uso excesivo. ¿Debo envolver cada lectura de esta bandera booleana? Se inicializa en falso y solo establece una vez en verdadero cuando se solicita detener (si se solicita antes de que la tarea se complete).

Mis tutores aconsejaron proteger incluso a los bool porque la lectura / escritura puede no ser atómica. Creo que esta bandera de un solo disparo es la excepción que demuestra la regla?


La asignación booleana es atómica. Ese no es el problema.

El problema es que un hilo no puede ver cambios en una variable hecha por un hilo diferente debido al reordenamiento de la instrucción del compilador oa la CPU o al almacenamiento en memoria caché de datos (es decir, el hilo que lee el indicador booleano puede leer un valor almacenado en caché valor).

La solución es una valla de memoria, que de hecho está implícitamente agregada por las sentencias de bloqueo, pero para una sola variable es exagerada. Simplemente declararlo como std::atomic<bool> .


La respuesta, creo, es "depende". Si está usando C ++ 03, el subprocesamiento no está definido en el Estándar, y tendrá que leer lo que dicen su compilador y su biblioteca de subprocesos, aunque este tipo de cosas se suele llamar una "raza benigna" y es por lo general está bien .

Si usa C ++ 11, las razas benignas son un comportamiento indefinido. Incluso cuando el comportamiento indefinido no tiene sentido para el tipo de datos subyacente. El problema es que los compiladores pueden suponer que los programas no tienen un comportamiento indefinido y realizar optimizaciones basadas en eso (consulte también la Parte 1 y la Parte 2 vinculadas desde allí). Por ejemplo, su compilador podría decidir leer el indicador una vez y almacenar en caché el valor porque es un comportamiento indefinido escribir en la variable en otro hilo sin algún tipo de mutex o barrera de memoria.

Por supuesto, puede ser que su compilador prometa no hacer esa optimización. Tendrás que mirar.

La solución más fácil es usar std::atomic<bool> en C ++ 11, o algo así como los atom_ops de Hans Boehm en otros lugares.


No, debe proteger todos los accesos, ya que los compiladores modernos y las CPU modifican el código sin tener en cuenta sus tareas de subprocesamiento múltiple. El acceso de lectura de diferentes subprocesos podría funcionar, pero no tiene que funcionar.


Nunca está bien leer algo posiblemente modificado en un hilo diferente sin sincronización. El nivel de sincronización que se necesita depende de lo que realmente está leyendo. Para los tipos primitivos, debería echar un vistazo a las lecturas atómicas, por ejemplo, en forma de std::atomic<bool> .

La razón por la cual la sincronización siempre es necesaria es que los procesadores tendrán los datos posiblemente compartidos en una línea de caché. No tiene ninguna razón para actualizar este valor a un valor posiblemente modificado en un hilo diferente si no hay sincronización. Peor aún, si no hay sincronización, puede escribir el valor incorrecto si algo almacenado cerca del valor se cambia y se sincroniza.