QThread finished() connected to deletelater of a QObject

僤鯓⒐⒋嵵緔 提交于 2019-12-06 01:14:14

问题


I have thought a lot and read lot of articles before asking this question here. None of the articles gave me a proper answer.

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 object has the affinity of the new thread.

1 > Worker finished signal will call quit() on the thread. This will end the thread's event loop and initiates the thread finished signal.

2 > Worker finished signal is connected to the worker deleteLater(). According to deleteLater() documentation

**Schedules this object for deletion. The object will be deleted when control returns to the event loop. If the event loop is > not running

when this function is called (e.g. deleteLater() is called on an object before QCoreApplication::exec()), the object will be deleted once the event loop is started.

Note that entering and leaving a new event loop (e.g., by opening a modal dialog) will not perform the deferred deletion; for the object to be deleted, the control must return to the event loop from which deleteLater() was called.

Note: It is safe to call this function more than once; when the first deferred deletion event is delivered, any pending events for the object are removed from the event queue.**

So when there is no eventloop, since the thread is already exiting and it has already raised the finished signal and we will no longer start the same thread again. In this case the deleteLater() will never be handled since the event loop doesn't exist and and worker object will not be deleted at all. Does this not create a memory leak.?

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

If we think that swapping the two lines will fix the problem, then I have another question. QT clearly states that the order the slots getting called when a signal is emitted is undetermined

There are bunch of comments in the article link mentioned above . Even the author was not able to answer the question completely


回答1:


QThread will do a QCoreApplication::sendPostedEvents with a event type of QEvent::DeferredDelete after sending it's finished signal

in other words QThread will collect all pending deleteLaters and execute them after run returns

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




回答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;
}


来源:https://stackoverflow.com/questions/12114604/qthread-finished-connected-to-deletelater-of-a-qobject

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!