2012-08-24 26 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