c++ - qthread exec
moveToThread vs derivado de QThread en Qt (4)
¿Cuándo se debería moveToThread
sobre la subclasificación de QThread
?
Este enlace muestra que ambos métodos funcionan. ¿Sobre qué base debo decidir qué usar de esos dos?
Como punto de partida: no utilizar ninguno. En la mayoría de los casos, tiene una unidad de trabajo que desea ejecutar de forma asíncrona. Usa QtConcurrent::run
para eso.
Si tiene un objeto que reacciona a los eventos y / o usa temporizadores, es un objeto QObject
que no debe bloquearse y entrar en un hilo, tal vez compartido con otros objetos.
Dicho objeto también puede envolver las API de bloqueo.
QThread
nunca es necesario en la práctica. Es como subclasificar QFile
. QThread
es un mango de hilo. Envuelve un recurso del sistema. Sobrecargarlo es un poco tonto.
La respuesta simple es SIEMPRE. Cuando mueves el objeto para enhebrar:
- Es fácil escribir la prueba para el código
- es fácil refactorizar el código (puede usar un hilo pero no tiene que hacerlo).
- Usted no mezcla la funcionalidad del hilo con la lógica de negocios.
- no hay problema con la vida útil del objeto
Cuando subclases QThread
- es más difícil escribir la prueba
- El proceso de limpieza de objetos puede ser muy confuso y ocasionar errores extraños.
Hay una descripción completa del problema en el blog de Qt: Lo estás haciendo mal ...
QtConcurrent::run
también es muy útil.
Recuerde que, de forma predeterminada, las ranuras intentan saltar entre las pisadas cuando se asigna una señal desde otro objeto del hilo. Para detalles vea la documentación de Qt :: ConnectionType .
Me centraría en las diferencias entre los dos métodos. No hay una respuesta general que se adapte a todos los casos de uso, por lo que es bueno entender exactamente qué son para elegir el mejor que se adapte a su caso.
Utilizando moveToThread ()
moveToThread () se usa para controlar la afinidad del subproceso del objeto , lo que básicamente significa establecer el subproceso (o, mejor, el bucle de eventos Qt) desde el cual el objeto emitirá señales y sus ranuras se ejecutarán.
Como se muestra en la documentación que vinculó, esto puede usarse para ejecutar código en un subproceso diferente, básicamente creando un trabajador ficticio , escribiendo el código para ejecutarse en una ranura pública (en el ejemplo, la ranura doWork () ) y luego usando moveToThread para moverlo a un bucle de evento diferente.
Entonces, se dispara una señal conectada a esa ranura. Dado que el objeto que emite la señal (el Controlador en el ejemplo) vive en un subproceso diferente, y la señal está conectada a nuestro método doWork con una conexión en cola, el método doWork se ejecutará en el subproceso de trabajo.
La clave aquí es que está creando un nuevo bucle de eventos , ejecutado por el subproceso de trabajo. Por lo tanto, una vez que la ranura doWork haya comenzado, todo el bucle de eventos estará ocupado hasta que salga, y esto significa que las señales entrantes se pondrán en cola.
Subclase QThread ()
El otro método descrito en la documentación de Qt es la subclasificación de QThread. En este caso, se anula la implementación predeterminada del método QThread :: run (), que crea un bucle de eventos, para ejecutar otra cosa.
No hay nada de malo en este enfoque en sí, aunque hay varias capturas.
En primer lugar, es muy fácil escribir código no seguro, porque el método run () es el único en esa clase que se ejecutará en otro subproceso.
Si, como ejemplo, tiene una variable miembro que inicializa en el constructor y luego utiliza en el método run () , su miembro se inicializa en el subproceso de la persona que llama y luego se usa en el nuevo subproceso.
La misma historia para cualquier método público que pueda llamarse desde la persona que llama o dentro de run ().
También se ejecutarán ranuras desde el hilo de la persona que llama, (a menos que hagas algo realmente extraño como moveToThread (esto) ), lo que genera una confusión adicional.
Entonces, es posible, pero realmente está solo con este enfoque y debe prestar atención adicional.
Otros enfoques
Por supuesto, hay alternativas a ambos enfoques, dependiendo de lo que necesite. Si solo necesita ejecutar algún código en segundo plano mientras se está ejecutando el subproceso de su GUI, puede considerar usar QtConcurrent::run() .
Sin embargo, tenga en cuenta que QtConcurrent utilizará el QThreadPool global. Si todo el grupo está ocupado (lo que significa que no hay subprocesos disponibles en el grupo), su código no se ejecutará de inmediato.
Otra alternativa, si está al menos en C ++ 11, es usar una API de nivel inferior como std::thread .
QThread es una abstracción de subprocesos de bajo nivel, primero QtConcurrent módulo QtConcurrent API de alto nivel y QRunnable
Si nada de esto es adecuado para usted, entonces lea este artículo anterior , le indicará cómo debe usar QThread. Piense en el hilo y la tarea realizada en este hilo como objetos separados, no los mezcle.
Por lo tanto, si necesita escribir envoltorio personalizado, específico o extendido de subprocesos, debe subclase QThread.
Si tiene una clase derivada de QObject con señales y ranuras, entonces use moveToThread en ella.
En otros casos, use QtConcurrent, QRunnable y QThreadPoll.