Sincronización de subprocesos
Aunque el propósito de los hilos es permitir que el código se ejecute en paralelo, hay ocasiones en las que los hilos deben detenerse y esperar a otros hilos. Por ejemplo, si dos hilos intentan escribir simultáneamente en la misma variable, el resultado es indefinido. El principio de obligar a los subprocesos a esperar unos a otros se denomina exclusión mutua. Es una técnica común para proteger recursos compartidos como los datos.
Qt proporciona primitivas de bajo nivel así como mecanismos de alto nivel para sincronizar hilos.
Primitivas de sincronización de bajo nivel
QMutex es la clase básica para aplicar la exclusión mutua. Un hilo bloquea un mutex para acceder a un recurso compartido. Si un segundo hilo intenta bloquear el mutex mientras ya está bloqueado, el segundo hilo será puesto en reposo hasta que el primer hilo complete su tarea y desbloquee el mutex.
QReadWriteLock es similar a QMutex, salvo que distingue entre acceso de "lectura" y "escritura". Cuando no se está escribiendo en un dato, es seguro que varios subprocesos lean de él simultáneamente. Un QMutex obliga a varios lectores a turnarse para leer datos compartidos, pero un QReadWriteLock permite la lectura simultánea, mejorando así el paralelismo.
QSemaphore es una generalización de QMutex que protege un cierto número de recursos idénticos. Por el contrario, un QMutex protege exactamente un recurso. El ejemplo Producer and Consumer using Semaphores muestra una aplicación típica de los semáforos: sincronizar el acceso a un buffer circular entre un productor y un consumidor.
QWaitCondition sincroniza los hilos no aplicando la exclusión mutua, sino proporcionando una variable de condición. Mientras que las otras primitivas hacen que los hilos esperen hasta que se desbloquee un recurso, QWaitCondition hace que los hilos esperen hasta que se cumpla una condición concreta. Para permitir que los hilos en espera procedan, llame a wakeOne() para despertar a un hilo seleccionado al azar o a wakeAll() para despertarlos a todos simultáneamente. El ejemplo Productor y consumidor utilizando condiciones de espera muestra cómo resolver el problema productor-consumidor utilizando QWaitCondition en lugar de QSemaphore.
Nota: Las clases de sincronización de Qt dependen del uso de punteros correctamente alineados. Por ejemplo, no se pueden usar clases empaquetadas con MSVC.
Estas clases de sincronización pueden usarse para hacer un método thread safe. Sin embargo, al hacerlo se incurre en una penalización de rendimiento, que es la razón por la que la mayoría de los métodos Qt no se hacen thread safe.
Riesgos
Si un subproceso bloquea un recurso pero no lo desbloquea, la aplicación puede congelarse porque el recurso no estará disponible permanentemente para otros subprocesos. Esto puede ocurrir, por ejemplo, si se lanza una excepción y fuerza a la función actual a regresar sin liberar su bloqueo.
Otro escenario similar es un bloqueo. Por ejemplo, supongamos que el subproceso A está esperando a que el subproceso B desbloquee un recurso. Si el subproceso B también está esperando a que el subproceso A desbloquee un recurso diferente, entonces ambos subprocesos acabarán esperando eternamente, por lo que la aplicación se congelará.
Clases de conveniencia
QMutexLocker QReadLocker y son clases de conveniencia que facilitan el uso de y . Bloquean un recurso cuando se construyen, y lo desbloquean automáticamente cuando se destruyen. Están diseñadas para simplificar el código que utiliza y , reduciendo así las posibilidades de que un recurso quede bloqueado permanentemente por accidente. QWriteLocker QMutex QReadWriteLock QMutex QReadWriteLock
Colas de eventos de alto nivel
El sistema de eventos de Qt es muy útil para la comunicación entre hilos. Cada hilo puede tener su propio bucle de eventos. Para llamar a un slot (o a cualquier método de invokable ) en otro subproceso, coloque esa llamada en el bucle de eventos del subproceso de destino. Esto permite que el subproceso de destino termine su tarea actual antes de que el slot comience a ejecutarse, mientras que el subproceso original continúa ejecutándose en paralelo.
Para colocar una invocación en un bucle de eventos, haz una conexión señal-ranura en cola. Cada vez que se emita la señal, sus argumentos serán registrados por el sistema de eventos. El hilo que el receptor de la señal lives in ejecutará entonces la ranura. Alternativamente, llame a QMetaObject::invokeMethod() para conseguir el mismo efecto sin señales. En ambos casos, se debe utilizar un queued connection porque un direct connection pasa por alto el sistema de eventos y ejecuta el método inmediatamente en el hilo actual.
No hay riesgo de bloqueos cuando se utiliza el sistema de eventos para la sincronización de hilos, a diferencia del uso de primitivas de bajo nivel. Sin embargo, el sistema de eventos no impone la exclusión mutua. Si los métodos invocables acceden a datos compartidos, deben protegerse con primitivas de bajo nivel.
Dicho esto, el sistema de eventos de Qt, junto con las estructuras de datos compartidas implícitamente, ofrece una alternativa al bloqueo de hilos tradicional. Si se usan exclusivamente señales y ranuras y no se comparten variables entre hilos, un programa multihilo puede prescindir completamente de las primitivas de bajo nivel.
Véase también QThread::exec() y Threads y QObjects.
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.