I'm confused about threads and event loops in Qt.
A QThread normally runs exec()
in run()
. But when you override run()
, there will not be an event loop.
This (older) doc states that calling deleteLater()
on objects that are created in a thread without an event loop doesn't work:
If no event loop is running, events won't be delivered to the object. For example, if you create a QTimer object in a thread but never call exec(), the QTimer will never emit its timeout() signal. Calling deleteLater() won't work either. (These restrictions apply to the main thread as well.)
However, look at the following code:
class MyObject : public QObject
{
Q_OBJECT
QString content;
public:
MyObject(QObject *parent = 0);
~MyObject();
};
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
signals:
public slots:
};
MyObject::MyObject(QObject *parent) :
QObject(parent),
content("foobar")
{}
MyObject::~MyObject()
{
// This code is still executed before I close the program. How?
qDebug() << "Destroying MyObject";
}
MyThread::MyThread(QObject *parent) :
QThread(parent)
{}
void MyThread::run()
{
// Creating a heap object in a thread that does not have
// an event loop (because I reimplemented run()).
MyObject * objectification = new MyObject();
sleep(1);
objectification->deleteLater();
}
So why does the deletelater()
call still post an event that is picked up?
As the Qt docs state for deleteLater: -
Since Qt 4.8, if deleteLater() is called on an object that lives in a thread with no running event loop, the object will be destroyed when the thread finishes.
The object is still being deleted when no event loop exists. If you look at the source code for QObject::deleteLater, you'll see that an event is posted:-
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
So, let's look at what happens when a thread is deleted. QThreadData's destructor includes this:-
for (int i = 0; i < postEventList.size(); ++i) {
const QPostEvent &pe = postEventList.at(i);
if (pe.event) {
--pe.receiver->d_func()->postedEvents;
pe.event->posted = false;
delete pe.event;
}
}
As we see, although there's no event loop, the event list is still available.
If we look more closely into QThreadPrivate (just taking one platform as an example, in this case unix), you'll see that when the thread finishes, it forwards all deferred deleted messages, so they can continue to be processed:
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With