2012-08-24 6 views
5

Ho pensato molto e letto molti articoli prima di fare questa domanda qui. Nessuno degli articoli mi ha dato una risposta adeguata.QThread finished() collegato a deletelater di 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(); 

oggetto lavoratore ha affinità del nuovo filo.

1> Il segnale del lavoratore finito chiamerà quit() sul thread. Questo interromperà il loop eventi del thread e avvia il segnale finito del thread.

2> Il segnale di lavoro finito è collegato al worker deleteLater(). Secondo la documentazione di deleteLater()

** Pianifica questo oggetto per la cancellazione. L'oggetto verrà cancellato quando il controllo ritorna al ciclo degli eventi. Se il ciclo degli eventi è> non è in esecuzione

quando questa funzione viene chiamata (ad esempio deleteLater() viene chiamato su un oggetto prima QCoreApplication :: exec()), l'oggetto verrà cancellato una volta avviato il ciclo di eventi.

Nota che entrare e uscire da un nuovo ciclo di eventi (ad esempio aprendo una finestra di dialogo modale) non eseguirà la cancellazione posticipata di ; per l'oggetto da eliminare, il controllo deve tornare al ciclo di eventi da cui è stato chiamato deleteLater().

Nota: It è possibile chiamare questa funzione più di una volta; quando il primo evento differita eliminazione viene consegnato, tutti gli eventi in corso per l'oggetto vengono rimossi dalla coda degli eventi. **

Così, quando non v'è alcuna eventloop, dal momento che il filo è già uscendo e che ha già sollevato il segnale finito e non avremo più riavviato lo stesso thread. In questo caso, deleteLater() non verrà mai gestito poiché il ciclo di eventi non esiste e l'oggetto di lavoro non verrà eliminato. Questo non crea una perdita di memoria?

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

Se pensiamo che lo scambio delle due linee risolverà il problema, allora ho un'altra domanda. QT indica chiaramente che l'ordine di chiamata degli slot quando viene emesso un segnale è indeterminato

Ci sono molti commenti nel collegamento dell'articolo sopra menzionato. Anche l'autore non è stato in grado di rispondere alla domanda completamente

risposta

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

non puoi cancellare il lavoratore nel thread oggetto creato. poiché è già stato spostato nella discussione usando moveToThread. Puoi spiegare questo. – Srikan

+0

Inoltre, consiglierei di assegnare un genitore a 'QThread'.Poiché l'istanza di 'QThread' è parte del thread in cui è stato generato (diversamente da qualsiasi oggetto che è stato spostato su di esso o il suo metodo' run() ') è perfettamente sicuro fare' thread = new QThread (this); 'if' thread' deve essere parte di qualche altra classe. In generale, dovresti evitare di chiamare 'delete' se esiste una soluzione non manuale migliore. Persino nel C++ standard ci sono dei puntatori intelligenti e ciò che non richiede l'eliminazione manuale delle spalle. – rbaleksandar

Problemi correlati