2012-08-24 14 views
5

He pensado mucho y he leído muchos artículos antes de hacer esta pregunta aquí. Ninguno de los artículos me dio una respuesta adecuada.QThread finished() conectado a deletelater de un QObject

http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

QThread* thread = new QThread; 
Worker* worker = new Worker(); 
worker->moveToThread(thread); 
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 
connect(thread, SIGNAL(started()), worker, SLOT(process())); 
connect(worker, SIGNAL(finished()), thread, SLOT(quit())); 
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
thread->start(); 

objeto trabajador tiene la afinidad de la nuevo hilo.

1> La señal terminada del trabajador llamará a quit() en el hilo. Esto finalizará el ciclo de eventos de la secuencia e iniciará la señal de finalización de la secuencia.

2> La señal de terminado del trabajador está conectada al trabajador deleteLater(). De acuerdo con la documentación deleteLater()

** Programa este objeto para su eliminación. El objeto se eliminará cuando el control vuelva al bucle de evento. Si el bucle de eventos es> no se está ejecutando

cuando esta función se llama (por ejemplo deleteLater() se llama en un objeto antes QCoreApplication :: exec()), el objeto se borrará una vez que se inicia el ciclo de eventos.

Tenga en cuenta que al ingresar y salir de un nuevo ciclo de evento (por ejemplo, al abrir un diálogo modal) no se realizará la eliminación diferida ; para el objeto que se va a eliminar, el control debe volver al bucle de evento desde el que se invocó deleteLater().

Nota: Es es seguro llamar a esta función más de una vez; cuando se entrega el primer evento supresión diferido, cualquier eventos pendientes para el objeto se eliminan de la cola de eventos. **

Así que cuando no hay eventloop, ya que el hilo ya está saliendo y que ya ha planteado la señal terminada y ya no volveremos a iniciar el mismo hilo. En este caso, deleteLater() nunca será manejado ya que el bucle de evento no existe y el objeto de trabajo no se eliminará en absoluto. ¿Esto no crea una pérdida de memoria?

connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
connect(worker, SIGNAL(finished()), thread, SLOT(quit())); 

Si pensamos que el intercambio de las dos líneas resolverá el problema, entonces tengo otra pregunta. QT indica claramente que el orden en que se llaman las ranuras cuando se emite una señal es indeterminado

Hay un montón de comentarios en el enlace del artículo mencionado anteriormente. Incluso el autor no fue capaz de responder a la pregunta completamente

Respuesta

2
//! put the following code in constructor 
QThread *thread = new QThread; 
//! type of m_weakThread is QWeakPointer<QThread> 
m_weakThread = thread; 
Worker *worker = new Worker; 
//! type of m_weakWorker is QWeakPointer<Worker> 
m_weakWorker = worker; 
worker->moveToThread(thread); 
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString))); 
connect(thread, SIGNAL(started()), worker, SLOT(process())); 
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); 
//! instead of finished() signal, connect destroyed() signal to thread's quit() slot 
connect(worker, SIGNAL(destroyed()), thread, SLOT(quit())); 
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
thread->start(); 

//! put the following code in destructor 
if (!m_weakThread.isNull()) { 
    QThread *thread = m_weakThread.data(); 
    if (thread->isRunning()) { 
     thread->quit(); 
     thread->wait(); 
    } 
} 
if (!m_weakWorker.isNull()) { 
    Worker *worker = m_weakWorker.data(); 
    m_weakWorker.clear(); //! optional, a little optimization 
    //! it's safe to release worker since the secondary thread exits 
    delete worker; 
} 
if (!m_weakThread.isNull()) { 
    QThread *thread = m_weakThread.data(); 
    m_weakThread.clear(); 
    //! it's safe to release thread since it exits and all objects in it has released 
    delete thread; 
} 
+0

no se puede eliminar el trabajador en el hilo objeto creado. ya que ya se ha movido al hilo usando moveToThread. Puede explicar esto. – Srikan

+0

También aconsejaría asignar un padre a 'QThread'.Dado que la instancia de 'QThread' es parte del hilo donde se engendró (a diferencia de cualquier objeto que se haya movido a él o su método' run() ') es perfectamente seguro hacer' thread = new QThread (this); 'if' thread' es parte de alguna otra clase. En general, debe evitar llamar a 'delete' si hay una mejor solución no manual. Incluso en el estándar C++ usted tiene punteros inteligentes y lo que no toma la carga de la limpieza manual de sus hombros. – rbaleksandar

Cuestiones relacionadas