2012-08-24 28 views
5

我在這裏提出這個問題之前已經想了很多,並閱讀了很多文章。沒有一篇文章給了我一個正確的答案。QThread finished()連接到刪除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(); 

工對象具有新線程的親和性。

1>工人完成的信號將在線程上調用quit()。這將結束線程的事件循環並啓動線程完成信號。

2>工人完成信號連接到工人deleteLater()。根據deleteLater()文檔

**計劃此對象的刪除。 控件返回到事件循環時,該對象將被刪除。如果事件循環是>沒有運行

時調用此函數(例如deleteLater()被調用QCoreApplication之前 對象:: EXEC上()),對象將進行一次事件循環開始刪除 。

請注意,進入和離開新的事件循環(例如通過打開模式對話框)將不會執行延遲刪除操作;對於要刪除的對象,控件必須 返回調用deleteLater()的事件循環。

注意:它 可以安全地多次調用此函數;當交付了首遞延 刪除事件,對象任何未決事件 從事件隊列中刪除。**

所以在沒有事件循環,因爲線程已經退出,並已經提出了完成的信號,我們將不再再次啓動相同的線程。在這種情況下,deleteLater()永遠不會被處理,因爲事件循環不存在,並且worker對象根本不會被刪除。這是否會造成內存泄漏?

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

如果我們認爲交換兩條線可以解決問題,那麼我還有一個問題。 QT明確指出,信號發射時槽被調用的順序不確定

上面提到的文章鏈接中有很多評論。就連筆者沒能回答這個問題完全

回答

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

不能刪除的工人所創建的對象的線程:後run返回

源執行。因爲它已經使用moveToThread移動到線程。你能解釋一下嗎? – Srikan

+0

另外我會建議分配一個父'QThread'。由於'QThread'的實例是它生成的線程的一部分(不同於任何移動到它或它的'run()'方法的對象),執行'thread = new QThread(this)是完全安全的。 '如果'線程'是其他類的一部分。一般來說,如果有更好的非手動解決方案,應該避免調用delete。即使在標準C++中,您也可以使用智能指針,而不需要手動清理肩膀的負擔。 – rbaleksandar