Red de conocimiento informático - Problemas con los teléfonos móviles - Cómo usar qthread para iniciar múltiples hilos

Cómo usar qthread para iniciar múltiples hilos

1. Introducción

Los subprocesos múltiples son útiles para aplicaciones que necesitan manejar tareas que requieren mucho tiempo, como responder a las acciones del usuario, actualizar pantallas y realizar operaciones que requieren mucho tiempo "en "en segundo plano", como ejecutar cálculos pesados, copiar archivos grandes y transferirlos a través de redes).

Al desarrollar aplicaciones utilizando el marco Qt, puede utilizar la clase QThread para crear y gestionar múltiples subprocesos de forma rápida y sencilla. También puede utilizar el mecanismo exclusivo de "señales y ranuras" de Qt para implementar la comunicación entre múltiples subprocesos.

El siguiente ejemplo utiliza la copia de archivos como ejemplo. El hilo principal es responsable de proporcionar una interfaz interactiva, mostrar el progreso de la copia, etc.; el hilo secundario es responsable de copiar archivos. Finalmente, hay código para ejecutar.

2. Uso de QThread 1: sobrecargar la función run()

El primer uso es escribir su propia clase, heredar QThread y sobrecargar su función run().

Como sabes, un programa C/C++ comienza con la función main(), que es el punto de entrada del proceso principal. Cuando la función main() sale, el proceso principal sale y todo el proceso. termina.

Para los procesos creados con Qthread, la función run() es el punto de entrada del nuevo hilo, y la salida de la función run() significa la terminación del hilo. La copia de archivos se realiza exactamente en la función run().

Aquí se muestra un ejemplo de cómo copiar un archivo. Personaliza una clase que hereda de Qthread

CopyFileThread: public QThread

{

Q_OBJECTpublic:

CopyFileThread(QObject * parent = 0 ) ; protected: void run(); // nueva entrada de hilo // omitir algún contenido}

En el archivo cpp correspondiente, defina run()

void CopyFileThread: run ( ){ // Nueva entrada de hilo

//La inicialización y las operaciones se colocan aquí}

Después de escribir la clase, genere una instancia de CopyFileThread en el código del hilo principal, por ejemplo, en la ventana principal .c en. Por ejemplo, en mainwindow.cpp:

// mainwindow.h CopyFileThread * m_cpyThread;// mainwindow.cpp m_ cpyThread = new CopyFileThread;

Cuando desee comenzar a copiar, p. , después de presionar el botón "Copiar", deje que este hilo comience a ejecutarse:

m_cpyThread->start();

Tenga en cuenta que la función start() se utiliza para iniciar el hijo. hilo y no ejecutar ().

Después de que el hilo comience a ejecutarse, irá a la función run() para realizar la operación de copia del archivo. En este momento, la visualización y el funcionamiento del hilo principal no se ven afectados.

Si necesita manejar eventos que pueden ocurrir durante el proceso de copia, como la interfaz que muestra el progreso de la copia, el regreso de errores, etc., debe enviar una señal desde CopyFileThread con anticipación y conectarlo a La ranura de la ventana principal será manejada por estas funciones de ranura.

3. Uso 2 de QThread: moveToThread()

Si no desea personalizar un nuevo hilo para cada tarea realizada, puede personalizar la clase utilizada para completar la tarea y Permítales heredar de QObject, por ejemplo, personalizar una clase FileCopier para copiar archivos.

clase FileCopier: QObject público

{

Q_OBJECTpublic: FileCopier explícito (QObject *parent = 0); espacios públicos: void startCopying(); void cancelCopying( );

}

Tenga en cuenta que aquí definimos dos funciones de ranura, que se utilizan para iniciar y cancelar la replicación respectivamente.

Se crea una instancia de la clase en sí en el hilo principal, por ejemplo:

// private in mainwindow.h:

FileCopier* m_copier;//mainwindow. cpp, durante la inicialización

m_copier = new FileCopier;

En este momento m_copier todavía pertenece al hilo principal. Cuando se inicializa cpp

m_childThread = new QThread; // El hilo secundario en sí no es responsable de copiar

Luego use moveToThread() para mover m_copier al nuevo hilo. Tenga en cuenta que moveToThread() es una función pública de QObject, por lo que la clase FileCopier utilizada para copiar archivos debe heredar de QObject. La replicación aún no ha comenzado.

m_copier->moveToThread(m_childThread); // Mueve la instancia a un nuevo hilo y habilita el subproceso múltiple

m_childThread->start() // Inicia el hilo secundario

Nota: debe recordar iniciar el hilo secundario; de lo contrario, el hilo no podrá ejecutarse y la función m_copier no se ejecutará.

Para comenzar a copiar, debe utilizar el mecanismo de señal y ranura, que activará la ejecución de la función de ranura FileCopier. Por lo tanto, defina las señales y conéctelas con anticipación:

// SEÑALES en mainwindow.h: void startCopyRsquested();// mainwindow.cpp, durante la inicialización // Utilice el mecanismo de ranura de señal para emitir comandos de inicio

connect(this.SIGNAL(startCopyRsquested()),m_copier,SLOT(startCopying()));

Emite una señal cuando se presiona el botón "Copiar".

emit startCopyRsquested(); // Enviar señal

m_copier activa la función de ranura para comenzar a copiar archivos después de que otro hilo recibe la señal.

4. Preguntas frecuentes

4.1. ¿Se pueden realizar operaciones de interfaz de usuario en subprocesos secundarios?

Las operaciones de la interfaz de usuario en Qt (como crear y operar QMainWindow, QWidget, etc.) solo se pueden realizar en el hilo principal.

Esta restricción significa que no puedes usar QDialog, QMessageBox, etc. en un hilo nuevo. Por ejemplo, ¿cometiste un error al copiar un archivo en un hilo nuevo y quieres que aparezca un cuadro de diálogo para avisarte? Puede hacer esto, pero debe pasar el mensaje de error al hilo principal, que ejecutará la advertencia del cuadro de diálogo.

Entonces, la idea general es que el hilo principal es responsable de proporcionar la interfaz, mientras que el hilo secundario es responsable de una única tarea sin una interfaz de usuario e interactúa con el hilo principal a través de "señales y ranuras". ".

4.2. ¿Qué códigos en QThread pertenecen a subprocesos?

¿Las instancias de QThread y las clases heredadas de QThread (en adelante denominadas colectivamente QThread) pertenecen a nuevos hilos? La respuesta es: no.

Cabe señalar que la instancia de QThread en sí pertenece al hilo que la creó.

Por ejemplo, si crea un QThread en el hilo principal, entonces la instancia de QThread en sí pertenece al hilo principal. Por supuesto, QThread abrirá un nuevo hilo (el punto de entrada es ejecutar ()), pero QThread en sí no pertenece a este nuevo hilo. En otras palabras, ninguno de los miembros del propio QThread pertenece al nuevo hilo, ni tampoco las instancias obtenidas a través de new en el constructor QThread. Esta característica significa que si desea implementar operaciones de subprocesos múltiples, las instancias, variables, etc. que desea que pertenezcan al nuevo subproceso deben inicializarse, crear instancias, etc. en run(). El ejemplo dado en este artículo hace esto.

Si su programa multiproceso emite alertas sobre subprocesos mientras se ejecuta, considere si las distintas variables, instancias, etc. están colocadas en la ubicación correcta y si realmente están en el nuevo subproceso.

4.3. ¿Cómo comprobar si realmente se ha implementado el subproceso múltiple?

Puedes imprimir el hilo actual. Para todas las clases que heredan de QObject, como QMainwindow, QThread y varias clases personalizadas, puede ver el hilo actual llamando a QObject::thread() (que devuelve un puntero a QThread). Por ejemplo, use qDebug() para imprimir:

En una función en mainwindow.cpp, la función run() de QThread, o una función de una clase personalizada, escriba:

qDebug() << "Hilo actual:" << thread();

Compara punteros impresos en diferentes ubicaciones para ver si están en el mismo hilo.

5. Ejemplo

Este ejemplo implementa la copia multiproceso de archivos de texto.

Los archivos de muestra proporcionados se pueden compilar y ejecutar utilizando QtCreator. La interfaz es la siguiente (los diferentes sistemas operativos varían ligeramente):

Este ejemplo implementa los dos métodos descritos en este artículo y compara la replicación de un solo subproceso. Seleccione la casilla de verificación para elegir un método de copia diferente. Como puede ver, cuando se usa subprocesos múltiples, la interfaz no se congelará y la animación de la segunda barra de progreso también es continua, mientras que cuando se usa la copia de un solo subproceso, el botón cancelar no se moverá, la interfaz se congelará; la animación de la segunda barra de progreso se detendrá. La animación también se detendrá.

Dado que este ejemplo trata con un archivo pequeño, se agrega una espera a cada línea del archivo copiado para que el proceso de copia dure más y lo haga visible.

Código de muestra:

/Xia-Weiwen/CopyFile