2012-04-17 6 views
13

Tengo una aplicación donde tengo QOBJects que contienen todos un QNetworkAccessManager. Soy consciente de que se sugiere que solo lo tenga en cada aplicación, pero como estoy haciendo más de 6 llamadas al mismo tiempo, necesitaba tenerlo así. Entonces, así es como comienzo los hilos.El número de subprocesos aumenta mucho, incluso al eliminar los hilos

FileUploader *fileUploader = new FileUploader(_fileList); 
QThread *fileUploaderThread = new QThread(); 
fileUploader->moveToThread(fileUploaderThread); 

// uploader > model 
connect(fileUploader, SIGNAL(progressChangedAt(int)), _model, SLOT(reportProgressChanged(int)), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(statusChangedAt(int)), _model, SLOT(reportStatusChanged(int)), Qt::QueuedConnection); 
// uploader > its thread 
connect(fileUploader, SIGNAL(canceled()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
// uploader > this 
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finishedCurrentUpload()), this, SLOT(uploadNextFileOrFinish()), Qt::QueuedConnection); 
// thread > this 
connect(fileUploaderThread, SIGNAL(finished()), this, SLOT(checkIfAllThreadsAreFinished()), Qt::QueuedConnection); 
connect(fileUploaderThread, SIGNAL(finished()), this, SLOT(deleteFinishedThread()), Qt::QueuedConnection); 
// this > uploader 
connect(this, SIGNAL(cancel()), fileUploader, SLOT(cancel()), Qt::QueuedConnection); 

fileUploaderThread->start(); 
QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection); 
QMetaObject::invokeMethod(fileUploader, "uploadAt", Qt::QueuedConnection, Q_ARG(int, startIndex)); 

QMutexLocker locker(&_mutex); 
_threadCount++; 

Cada tema se inicia con un índice a una lista para que puedan ir a buscar lo que necesitan para cargar y continuar unos 5 pasos (llamadas con el QNetworkAccessManager). Cuando no hay más elementos a cargar, las señales FileUploader "acabado()" que llama a la deleteFinishedThread y deleteFinishedUploader donde hago:

QThread *thread = qobject_cast<QThread*>(sender()); 

if(thread != NULL) thread->deleteLater(); 

o

FileUploader *fileUploader = qobject_cast<FileUploader*>(sender()); 

if(fileUploader != NULL) fileUploader->deleteLater(); 

Estos se supone que debe eliminar los hilos cuando están hechos.

El problema es que cada vez que comienzo (por ejemplo) 3 subprocesos que tienen 1 archivo para cargar y manejar cada uno, el conteo de subprocesos aumenta en 8-10. Esto significa que el recuento de subprocesos va de aproximadamente 5 a 100 si reinicio el proceso de carga varias veces.

¿Qué estoy haciendo mal? ¿O es mi mayor problema que use el "Administrador de tareas de Windows" para controlar esto? Estoy manejando todas las respuestas del QNAM que elimino y todo parece borrarse, pero aún me estoy rascando cuando el conteo de hilos sigue aumentando ...

EDIT: En mi fileuploader creo un objeto (Administrador) en el montón que tiene un QNetworkAccessManager en la pila. Cuando el fileuploader se elimina, se llama a "deleteLater()" en el Administrador, pero nunca se elimina. Intentamos eliminar el Administrador y establecerlo en NULO, pero eso nos dio una infracción de acceso ya que el Administrador aún no había finalizado (el QNetwork.dll informó el problema, por lo que debe ser algo dentro del QNAM que todavía se esté ejecutando). Los momentos en los que no obtuvimos una infracción de acceso, el objeto se eliminó y el recuento de subprocesos volvió a la normalidad. ¿Qué puede vivir dentro de QNAM y evitar que lo elimine cuando se sale del alcance? ¿Debo crear el QNAM en el montón? En esta etapa no de los destructores están siendo llamados, incluso cuando se llama a deleteLater() ...

Además, ¿cómo puedo reducir el mango cuenta?

+1

agregó una recompensa. su pregunta necesita un poco de amor ... – UmNyobe

+0

oh muchas gracias. Hiciste mi día :) – chikuba

+0

un comentario: si todavía los usas, llama a 'QMetaObject :: invokeMethod (' antes de iniciar 'fileUploaderThread'. Es la mejor manera de asegurarte de que estas ranuras se llamen primero cuando se inicie el ciclo de subprocesos. – UmNyobe

Respuesta

1

Después de mucho "casi darme por vencido", se me ocurrió una solución para los hilos. Es verdad lo que dijo Synxis sobre el orden de las máquinas tragamonedas.

Todavía tengo algunos problemas con los manejadores de archivos, y si alguien tiene una respuesta mejor que la mía, me complace aceptar eso.

he cambiado de código para:

... 
// uploader > this 
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
// uploader > its thread 
connect(fileUploader, SIGNAL(destroyed()), fileUploaderThread, SLOT(quit())); 

Esto significa que el hilo se detuvo (quit()) cuando se elimina el objeto de conseguir. Esto realmente funciona aunque la documentación indique:

Esta señal se emite inmediatamente antes de que se destruya el objeto obj, y no se puede bloquear.

Todos los objetos de los niños se destruyen inmediatamente después de que se emite esta señal.

Lo que significa que estas señales se emiten justo ANTES de que algo se destruya (lo que significaría que cerraría el hilo antes de que el cargador se borrara). No es lo suficientemente bueno y podría ser una mejor manera. SIN EMBARGO, atm, mi conteo de hilos baja un poco cada vez que termina la carga y vuelve a la normalidad después de unos 20 segundos (algunos "hilos de observación" deben ser eliminados por Windows, etc.).

+0

Buena solución para las ranuras. ¿Cómo se gestionan/crean/eliminan los identificadores de archivos? ¿Cuál es el problema con ellos? – Synxis

+0

im no estoy muy seguro. tener algo de experiencia con C# y cómo lo haces entonces, pero todo lo que puedo ver ahora es que el número de identificadores aumenta pero no disminuye – chikuba

+0

el problema es que no estoy seguro si se elimina el hilo antes de que se destruyan los objetos. .. – chikuba

7

puedo estar equivocado, pero creo que hay un problema con las señales:

// uploader > its thread 
connect(fileUploader, SIGNAL(canceled()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), fileUploaderThread, SLOT(quit()), Qt::QueuedConnection); 
// uploader > this 
connect(fileUploader, SIGNAL(canceled()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 
connect(fileUploader, SIGNAL(finished()), this, SLOT(deleteFinishedUploader()), Qt::QueuedConnection); 

recordar que cuando múltiples ranuras están conectados a la misma señal, que están ejecutados en el orden de conexión. Aquí, cuando se termine fileUploader, se llamará al finished() que primero llamará al método quit() del subproceso y luego al método deleteFinishedUploader(). Lo mismo para la señal canceled(). Pero, mientras tanto, el subproceso se terminó, por lo que no se puede procesar el evento para el archivo de carga (consecuencia del moveToThread(...)). deleteLater() necesidades de procesamiento de eventos, por lo tanto nunca se borrará tu FileUploader ...

no estoy al 100% que la organización de sus conexiones en el otro lado va a hacer las cosas de trabajo: la deleteLater() puede ser llamado y el hilo salieron immediatelly después, sin procesamiento de eventos.

La solución podría ser volver a moveToThread() fileUploader al hilo principal oa un hilo que aún procese su bucle de evento.

2

No es una respuesta, pero:

fileUploaderThread->start(); 
    QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection); 
    QMetaObject::invokeMethod(fileUploader, "uploadAt", Qt::QueuedConnection, Q_ARG(int, startIndex)); 

significa iniciar el bucle de par, y luego hacer cola ranuras o señales para ser ejecutado .. Supongamos que (en general) que hay otros QObject en este hilo. Es posible que estos obtengan sus ranuras o señales ejecutadas porque el bucle de eventos ya ha comenzado. Si desea que "init" y "uploadAt" sean los primeros métodos invocados cuando se ejecuta el bucle de evento, debe ponerlos en cola antes de iniciar el bucle de evento (si el hilo no se inicia, nunca se ejecutarán).

De QMetaObject::invokeMethod:

Si el tipo es Qt :: QueuedConnection, un QEvent será enviada y el miembro se invoca tan pronto como la aplicación entra en el bucle de eventos principal.

En este caso, el evento se envía al bucle de evento de la secuencia.

+0

oh bien. muy bueno saber gracias! sin embargo, en este ejemplo, podría limitarme a lo que he obtenido ya que el cargador será el único elemento en ese hilo :) – chikuba

Cuestiones relacionadas