8

在这里问这个问题之前,我想了很多,阅读了很多文章。没有一篇文章给我一个正确的答案。

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();

Worker 对象具有新线程的亲和性。

  1. 工人完成信号将调用quit()线程。这将结束线程的事件循环并启动线程完成信号。

  2. 工人finished信号连接到工人deleteLater()。根据deleteLater()文档

计划删除此对象。当控制返回事件循环时,该对象将被删除。如果调用此函数时事件循环没有运行(例如deleteLater(),在之前对对象调用过QCoreApplication::exec()),则一旦启动事件循环,该对象将被删除。

请注意,进入和离开新的事件循环(例如,通过打开模式对话框)不会执行延迟删除;对于要删除的对象,控件必须返回到从中deleteLater()调用的事件循环。

注意:多次调用该函数是安全的;当第一个延迟删除事件被传递时,该对象的所有未决事件都将从事件队列中删除。**

所以当没有事件循环时,因为线程已经退出并且它已经提出了完成信号,我们将不再再次启动同一个线程。在这种情况下,deleteLater()将永远不会处理,因为事件循环不存在,并且工作对象根本不会被删除。这不会造成内存泄漏。?

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

如果我们认为交换两条线可以解决问题,那么我还有另一个问题。QT 明确指出发出信号时调用槽的顺序是不确定的

上面提到的文章链接中有一堆评论。甚至作者也无法完全回答这个问题

4

2 回答 2

5

QThread 将在发送完成信号后执行一个事件类型为 QEvent::DeferredDelete的QCoreApplication::sendPostedEvents

换句话说,QThread 将收集所有待处理的 deleteLater 并在run返回后执行它们

来源:https ://qt.gitorious.org/qt/qtbase/source/c657bb7b51115d6e1719166fb502bb0ca1dcf4e8:src/corelib/thread/qthread_win.cpp#L363-462

于 2013-10-11T10:00:07.817 回答
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;
}
于 2012-10-12T12:48:25.010 回答