Let's consider a scenario of two QObjects
, senderObject
of type SenderObject
and receiverObject
of type ReceiverObject
. senderObject
has been created on a worker thread while receiverObject
has been created on the main thread. Now let's asssume SenderObject
has a signal somethingsChanged
and let's consider the following the code snippet:
Snippet1:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread t;
SenderObject senderObject = new SenderObject();
senderObject.moveToThread(&t);
ReceiverObject receiverObject = new ReceiverObject();
//in this case we know for a fact that receiverObject's
//onSomethingsChanged() will be called on the main thread
QObject::connect(senderObject, &SenderObject::somethingsChanged,
receiverObject, &ReceiverObject::onSomethingsChanged, Qt::QueuedConnection);
t.start();
return a.exec();
}
Now let's consider the following code snippet:
Snippet2:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread t;
SenderObject senderObject = new SenderObject();
senderObject.moveToThread(&t);
//where will qDebug() << "Hello, world" be executed?
//On the main thread again since the lambda lives on the main thread?
QObject::connect(senderObject, &SenderObject::somethingsChanged,
[]{qDebug << "Hello, world";});
t.start();
return a.exec();
}
Will the lambda in Snippet2 be execute on the main thread also since the lambda has been declared on the main thread, or will it get executed in the same thread as senderObject
?
Here's our class SenderObject:
class Sender : public QObject {
Q_OBJECT
public:
explicit Sender() : QObject() {
_timer.setInterval(1000);
connect(&_timer, &QTimer::timeout, this,
[this] { emit somethingsChanged(); });
_timer.start();
}
signals:
void somethingsChanged();
private:
QTimer _timer;
};
Since there is no overload of QObject::connect
that will take a lambda and a Qt
connection type parameter, Snippet2 will execute in the sender's thread, which is a worker thread.
In order to force the lambda to execute on the main thread, here is a workaround:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread t;
SenderObject senderObject = new SenderObject();
senderObject.moveToThread(&t);
QObject::connect(senderObject, &SenderObject::somethingsChanged, new QObject,
[]{qDebug << "Hello, world";}, Qt::QueuedConnection);
t.start();
return a.exec();
}
Since new QObject
is called on the main thread, the lambda will also get executed on the main thread.
Or, if we don't like to see new
, this is what will work:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread t;
SenderObject senderObject = new SenderObject();
senderObject.moveToThread(&t);
QObject object;
QObject::connect(senderObject, &SenderObject::somethingsChanged, &object,
[]{qDebug << "Hello, world";}, Qt::QueuedConnection);
t.start();
return a.exec();
}
Or, even a better solution will be to use qApp
, which is an instance of the application and a singleton and available from anywhere.
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
QThread t;
SenderObject senderObject = new SenderObject();
senderObject.moveToThread(&t);
QObject::connect(senderObject, &SenderObject::somethingsChanged, qApp,
[]{qDebug << "Hello, world";}, Qt::QueuedConnection);
t.start();
return a.exec();
}