2012-08-24 3 views
5

J'ai beaucoup réfléchi et lu beaucoup d'articles avant de poser cette question ici. Aucun des articles m'a donné une réponse appropriée.QThread terminé() connecté à deletelater d'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(); 

objet travailleur a l'affinité du nouveau fil.

1> Le signal de fin de travail appellera quit() sur le fil. Cela met fin à la boucle d'événement du thread et initie le signal terminé.

2> Le signal de fin de travail est connecté au worker deleteLater(). Selon la documentation deleteLater()

** Planifie la suppression de cet objet. L'objet sera supprimé lorsque le contrôle reviendra à la boucle d'événements. Si la boucle d'événement est> ne fonctionne pas

lorsque cette fonction est appelée (par exemple deleteLater() est appelée sur un objet avant QCoreApplication :: exec()), l'objet sera supprimé une fois que la boucle d'événements est démarré.

Notez que l'entrée et la sortie d'une nouvelle boucle d'événements (par exemple, en ouvrant une boîte de dialogue modale) n'effectueront pas la suppression différée ; Pour que l'objet soit supprimé, le contrôle doit retourner à la boucle d'événements à partir de laquelle deleteLater() a été appelé.

Remarque: est sûr d'appeler cette fonction plus d'une fois; lorsque le premier événement différé de suppression est livré, les événements en attente de l'objet sont retirés de la file d'attente. **

Alors, quand il n'y a pas eventloop, puisque le fil est sortie déjà et il a déjà soulevé le signal terminé et nous ne recommencerons plus le même fil. Dans ce cas, deleteLater() ne sera jamais manipulé car la boucle d'événement n'existe pas et l'objet worker ne sera pas supprimé du tout. Cela ne crée-t-il pas une fuite de mémoire? Si nous pensons que l'échange des deux lignes permettra de résoudre le problème, alors j'ai une autre question. QT indique clairement que l'ordre dans lequel les slots sont appelés lorsqu'un signal est émis est indéterminé.

Il y a beaucoup de commentaires dans le lien d'article mentionné ci-dessus. Même l'auteur n'a pas été en mesure de répondre à la question complètement

Répondre

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

Vous ne pouvez pas supprimer le travailleur dans le thread d'objet créé. car il a déjà été déplacé vers le Thread en utilisant moveToThread. Pouvez-vous expliquer cela. – Srikan

+0

Aussi, je conseillerais d'assigner un parent à 'QThread'.Puisque l'instance de QThread fait partie du thread où elle a été générée (contrairement à tous les objets qui y ont été déplacés ou à sa méthode 'run()), il est parfaitement sûr de faire' thread = new QThread (this); 'si' thread 'doit faire partie d'une autre classe. En général, évitez d'appeler 'delete' s'il existe une meilleure solution non-manuelle. Même dans le standard C++, vous avez des pointeurs intelligents et ce qui ne prend pas la charge de nettoyage manuel de vos épaules. – rbaleksandar

Questions connexes