ConnectionType for connection between QThread::finished and QObject::deleteLater
-
I have this simple piece of code:
A simple qobject:
#include <QObject> class A : public QObject { Q_OBJECT public: A(); virtual ~A(); void start(); signals: void finished(); };
#include "a.h" #include <QDebug> #include <QThread> A::A() { } A::~A(){ qInfo() << "A deleted in thread " << QThread::currentThread(); } void A::start() { qInfo() << "do stuf..."; emit finished(); }
A main where the qobject is created and run in a secondary thread:
#include <QCoreApplication> #include <QDebug> #include <QThread> #include <QObject> #include "a.h" int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); qInfo() << "Main running in " << QThread::currentThread(); QThread *t = new QThread(); A* a = new A; a->moveToThread(t); QObject::connect(t, &QThread::started, a, &A::start); QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::QueuedConnection); // QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::DirectConnection); QObject::connect(a, &A::finished, [t]() { t->exit(0); }); t->start(); qInfo() << "t lives in " << t->currentThread(); return app.exec(); }
The connections between
QThread
andA
elements should beQueuedConnection
due to they live in different threads, but if theConnectionType
ofQThread::finished
andQObject::deleteLater
connection isQueuedConnection
, the object deleter will be never called.
If theConnectionType
of that connection isDirectConnection
,a
is deleted in its thread even though it should be executed on the main thread. Is this a bug with the event loop?This is the output of calling with
DirectConnection
:Main running in QThread(0x559f7c6c3e60) t lives in QThread(0x559f7c6c3e60) do stuf... in thread QThread(0x559f7c6c9540) A deleted in thread QThread(0x559f7c6c9540)
-
I have this simple piece of code:
A simple qobject:
#include <QObject> class A : public QObject { Q_OBJECT public: A(); virtual ~A(); void start(); signals: void finished(); };
#include "a.h" #include <QDebug> #include <QThread> A::A() { } A::~A(){ qInfo() << "A deleted in thread " << QThread::currentThread(); } void A::start() { qInfo() << "do stuf..."; emit finished(); }
A main where the qobject is created and run in a secondary thread:
#include <QCoreApplication> #include <QDebug> #include <QThread> #include <QObject> #include "a.h" int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); qInfo() << "Main running in " << QThread::currentThread(); QThread *t = new QThread(); A* a = new A; a->moveToThread(t); QObject::connect(t, &QThread::started, a, &A::start); QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::QueuedConnection); // QObject::connect(t, &QThread::finished, a, &A::deleteLater, Qt::DirectConnection); QObject::connect(a, &A::finished, [t]() { t->exit(0); }); t->start(); qInfo() << "t lives in " << t->currentThread(); return app.exec(); }
The connections between
QThread
andA
elements should beQueuedConnection
due to they live in different threads, but if theConnectionType
ofQThread::finished
andQObject::deleteLater
connection isQueuedConnection
, the object deleter will be never called.
If theConnectionType
of that connection isDirectConnection
,a
is deleted in its thread even though it should be executed on the main thread. Is this a bug with the event loop?This is the output of calling with
DirectConnection
:Main running in QThread(0x559f7c6c3e60) t lives in QThread(0x559f7c6c3e60) do stuf... in thread QThread(0x559f7c6c9540) A deleted in thread QThread(0x559f7c6c9540)
@Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:
but if the ConnectionType of QThread::finished and QObject::deleteLater connection is QueuedConnection, the object deleter will be never called.
This is normal,
QObject::deleteLater()
while schedule the deletion of the instance in the event queue to be executed on next iteration in event queue. This will ensure deletion will be done in instance working thread!
(cf. https://doc.qt.io/qt-5/qobject.html#deleteLater).To do it in the right order,
deleteLater()
should be called before emittingfinished signal
. -
@Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:
but if the ConnectionType of QThread::finished and QObject::deleteLater connection is QueuedConnection, the object deleter will be never called.
This is normal,
QObject::deleteLater()
while schedule the deletion of the instance in the event queue to be executed on next iteration in event queue. This will ensure deletion will be done in instance working thread!
(cf. https://doc.qt.io/qt-5/qobject.html#deleteLater).To do it in the right order,
deleteLater()
should be called before emittingfinished signal
.@KroMignon Thank you for your response.
According to qt documentation about
QThread::finished
:When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(), to free objects in that thread.
This is why I find confusing this behavior. I understand that the connection is OK (using
QueuedConnection
) and the deletion should be executed in the secondary thread (a
's thread). -
@KroMignon Thank you for your response.
According to qt documentation about
QThread::finished
:When this signal is emitted, the event loop has already stopped running. No more events will be processed in the thread, except for deferred deletion events. This signal can be connected to QObject::deleteLater(), to free objects in that thread.
This is why I find confusing this behavior. I understand that the connection is OK (using
QueuedConnection
) and the deletion should be executed in the secondary thread (a
's thread).@Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:
This is why I find confusing this behavior. I understand that the connection is OK (using QueuedConnection) and the deletion should be executed in the secondary thread (a's thread).
I don't understand what is confusing here?.
QThread
t is emittingfinished()
, which means the thread has stopped.
You could use this signal to connect todeleteLater()
on instancet
to also delete the thread instance (because this instance lives in the main thread) but not fora
(or you have to useQt::DirectConnection
). -
@Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:
This is why I find confusing this behavior. I understand that the connection is OK (using QueuedConnection) and the deletion should be executed in the secondary thread (a's thread).
I don't understand what is confusing here?.
QThread
t is emittingfinished()
, which means the thread has stopped.
You could use this signal to connect todeleteLater()
on instancet
to also delete the thread instance (because this instance lives in the main thread) but not fora
(or you have to useQt::DirectConnection
).@KroMignon I want to delete
a
.QThread::finished
signal is emitted from the main thread and I want to connect it toA:deleteLater
witha
object as receiver, which lives in another thread. So, I understand, I should useQueuedConnection
for this case (to execute it in the receiver's thread), but it doesn't work.
Instead, it works if I useDirectConnection
, even though the signal is emitted in the main thread and the slot is executed in another thread (DirectConnection
should execute the slot in the sender's thread). -
@KroMignon I want to delete
a
.QThread::finished
signal is emitted from the main thread and I want to connect it toA:deleteLater
witha
object as receiver, which lives in another thread. So, I understand, I should useQueuedConnection
for this case (to execute it in the receiver's thread), but it doesn't work.
Instead, it works if I useDirectConnection
, even though the signal is emitted in the main thread and the slot is executed in another thread (DirectConnection
should execute the slot in the sender's thread).@Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:
I want to delete a. QThread::finished signal is emitted from the main thread and I want to connect it to A:deleteLater with a object as receiver, which lives in another thread.
You doing things in the wrong order.
You should always delete the object in the thread in which they are running.
This means deletinga
before stopping threadt
.QThread *t = new QThread(); A* a = new A; a->moveToThread(t); // on thread start, start worker QObject::connect(t, &QThread::started, a, &A::start); // on worker done, delete worker QObject::connect(a, &A::finished, a, &A::deleteLater); // on worker deleted, stop worker thread QObject::connect(a, &QObject::destroyed, t, &QThread::quit); // on threa end, delete thread QObject::connect(t, &QObject::finished, t, &QThread::delteLater); t->start();
[EDIT]:
I made an error, toQObject::destroyed()
only works withQt::DirectConnection
because direct after calling all connection with instance are destroyed (cf. https://doc.qt.io/qt-5/qobject.html#destroyed)QObject::connect(a, &QObject::destroyed, t, &QThread::quit, Qt::DirectConnection);
A better way, would be to change as follow
QObject::connect(a, &A::finished, a, &A::deleteLater); QObject::connect(a, &A::finished, t, &QThread::quit);
-
@Fran-Sansone said in ConnectionType for connection between QThread::finished and QObject::deleteLater:
I want to delete a. QThread::finished signal is emitted from the main thread and I want to connect it to A:deleteLater with a object as receiver, which lives in another thread.
You doing things in the wrong order.
You should always delete the object in the thread in which they are running.
This means deletinga
before stopping threadt
.QThread *t = new QThread(); A* a = new A; a->moveToThread(t); // on thread start, start worker QObject::connect(t, &QThread::started, a, &A::start); // on worker done, delete worker QObject::connect(a, &A::finished, a, &A::deleteLater); // on worker deleted, stop worker thread QObject::connect(a, &QObject::destroyed, t, &QThread::quit); // on threa end, delete thread QObject::connect(t, &QObject::finished, t, &QThread::delteLater); t->start();
[EDIT]:
I made an error, toQObject::destroyed()
only works withQt::DirectConnection
because direct after calling all connection with instance are destroyed (cf. https://doc.qt.io/qt-5/qobject.html#destroyed)QObject::connect(a, &QObject::destroyed, t, &QThread::quit, Qt::DirectConnection);
A better way, would be to change as follow
QObject::connect(a, &A::finished, a, &A::deleteLater); QObject::connect(a, &A::finished, t, &QThread::quit);
Thank you very much @KroMignon.
It works properly with your last example.
I can add to this conversation that the connection that in my code this connection was wrong:
QObject::connect(a, &A::finished, [t]() { t->exit(0); });
Changing this connection for:
QObject::connect(a, &A::finished, t, &QThread::quit);
and the deletion using
QueuedConnection
that I was mentioning works properly.