¿Necesito un mutex para leer?

5 minutos de lectura

Tengo una clase que tiene un estado (una enumeración simple) y a la que se accede desde dos subprocesos. Para cambiar de estado, uso un mutex (boost::mutex). ¿Es seguro verificar el estado (por ejemplo, compare state_ == ESTABLECIDO) o tengo que usar el mutex también en este caso? En otras palabras, ¿necesito el mutex cuando solo quiero leer una variable que podría ser escrita simultáneamente por otro hilo?

avatar de usuario
jalf

Eso depende.

El lenguaje C++ no dice nada sobre subprocesos o atomicidad.

pero en la mayoría CPU modernas, leer un número entero es una operación atómica, lo que significa que siempre leerá un valor consistente, incluso sin un mutex.

Sin embargosin un mutex, o alguna otra forma de sincronización, el compilador y la CPU son libres de reordenar lecturas y escrituras, por lo que cualquier cosa más compleja, cualquier cosa que implique acceder a múltiples variables, sigue siendo insegura en el caso general.

Suponiendo que el subproceso del escritor actualice algunos datos y luego establezca un indicador de número entero para informar a otros subprocesos que los datos están disponibles, esto podría reordenarse para que se establezca el indicador antes de actualizando los datos. A menos que use un mutex u otra forma de barrera de memoria.

Entonces, si desea un comportamiento correcto, no necesita un mutex como tal, y no hay problema si otro subproceso escribe en la variable mientras lo está leyendo. Será atómico a menos que esté trabajando en una CPU muy inusual. Pero tu hacer necesita una barrera de memoria de algún tipo para evitar el reordenamiento en el compilador o la CPU.

  • A menos que especifique un volátil, la lectura (o la escritura) podría nunca ser realizado. Tarde o temprano no es suficiente.

    – Efraín

    16 de octubre de 2009 a las 12:34

  • Pero incluso con volátiles, la CPU o el compilador pueden reordenar las escrituras, haciéndolas sin sentido. La solución correcta es una barrera de memoria, y luego volátil es solo una desoptimización innecesaria.

    – jalf

    16 de octubre de 2009 a las 13:34

  • @jalf: No, si solo necesita una sola bandera. Vuelva a leer la pregunta.

    – Efraín

    17 de octubre de 2009 a las 16:14

  • Y probablemente sean las soluciones como las que usted propone las que conducen a gran parte del código inflado. No, NO necesitas una barrera para una sola bandera.

    – Efraín

    17 de octubre de 2009 a las 16:15

  • Pero si se está verificando una bandera para determinar el siguiente paso en su aplicación, (a) necesita compartir algunos otros datos entre subprocesos. (b) la verificación de la bandera no tiene sentido y siempre puede realizar los siguientes pasos. Suponiendo que (a) es el escenario, es posible que “otros datos” no estén listos solo porque la variable de marca está configurada. Suponiendo que se deba a la marca, es probable que se produzcan ejecuciones en depuración, bloqueos en la versión y compilación.

    – peter karasev

    13 de diciembre de 2012 a las 7:48


Tiene dos subprocesos, intercambian información, sí, necesita un mutex y probablemente también necesite una espera condicional.

En su ejemplo (compare state_ == ESTABLECIDO) indica que el subproceso n. ° 2 está esperando que el subproceso n. ° 1 inicie una conexión/estado. Sin un mutex o condicionales/eventos, el subproceso #2 tiene que sondear el estado continuamente.

Los subprocesos se utilizan para aumentar el rendimiento (o mejorar la capacidad de respuesta), el sondeo generalmente da como resultado una disminución del rendimiento, ya sea al consumir una gran cantidad de CPU o al introducir latencia debido al intervalo de sondeo.

  • +1 por sugerir variables condicionales. Por lo que parece, tiene un hilo que necesita responder a un cambio de estado por otro cambio. Si ese es el caso, las variables condicionales son mucho más apropiadas.

    – Falaína

    6 de octubre de 2009 a las 15:37

  • @Ermelli, ¿todavía necesitamos mutex si queremos usar el ciclo de espera ocupado de todos modos (porque el ciclo podría hacer otra cosa mientras tanto)

    – Nick

    7 de enero de 2017 a las 16:24


Sí. Si el subproceso a lee una variable mientras el subproceso b está escribiendo en él, puede leer un valor indefinido. Las operaciones de lectura y escritura no son atómicas, especialmente en un sistema multiprocesador.

  • mientras que un subproceso de escritor lo hace (buscar->escribir->almacenar) no veo cuándo en medio de esos un lector buscaría un valor indefinido, ya sea el anterior o el posterior, pero nunca indefinido.

    – Arkaitz Jiménez

    6 de octubre de 2009 a las 12:23

  • Teniendo en cuenta los valores de enumeración que se leen en una instrucción.

    – Arkaitz Jiménez

    6 de octubre de 2009 a las 12:26

  • @Arkaitz: indefinido probablemente no era la palabra correcta. Pero las arquitecturas de CPU/memoria se vuelven cada vez más complejas con niveles adicionales de caché, latencias aumentadas, etc. La respuesta es simple: ¡Di no! para compartir datos sin bloqueo. Incluso los expertos cometen muchos errores en esta área.

    – sellibitze

    6 de octubre de 2009 a las 13:21

En términos generales, no lo hace, si su variable se declara con “volátil”. Y SOLO si se trata de una sola variable; de ​​lo contrario, debe tener mucho cuidado con las posibles carreras.

en realidad, no hay razón para bloquear el acceso al objeto para lectura. solo desea bloquearlo mientras escribe en él. esto es exactamente lo que es un bloqueo de lector-escritor. no bloquea el objeto mientras no haya operaciones de escritura. mejora el rendimiento y evita interbloqueos. consulte los siguientes enlaces para obtener explicaciones más detalladas:

wikipedia
proyecto de código

avatar de usuario
aJ.

El acceso a la enumeración (lectura o escritura) debe estar protegido.

Otra cosa: si la contención del subproceso es menor y los subprocesos pertenecen al mismo proceso, entonces la sección crítica sería mejor que mutex.

¿Ha sido útil esta solución?