将信号连接到 lambda 时 Qt::QueuedConnection 和 Qt::DirectConnection 之间的区别
Difference between Qt::QueuedConnection and Qt::DirectConnection when connecting a signal to a lambda
让我们考虑两个 QObjects
、senderObject
类型 SenderObject
和 receiverObject
类型 ReceiverObject
的场景。 senderObject
已在工作线程上创建,而 receiverObject
已在主线程上创建。现在让我们假设 SenderObject
有一个信号 somethingsChanged
并且让我们考虑以下代码片段:
片段 1:
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();
}
现在让我们考虑以下代码片段:
片段 2:
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();
}
Snippet2 中的 lambda 是否也会在主线程上执行,因为 lambda 已在主线程上声明,还是会在与 senderObject
相同的线程中执行?
这是我们的 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;
};
由于没有 QObject::connect
的重载需要一个 lambda 和一个 Qt
连接类型参数,Snippet2 将在发送者的线程中执行,它是一个工作线程。
为了强制 lambda 在主线程上执行,这里有一个解决方法:
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();
}
由于new QObject
是在主线程上调用的,lambda也会在主线程上执行。
或者,如果我们不喜欢看到 new
,这将起作用:
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();
}
或者,更好的解决方案是使用 qApp
,它是应用程序的实例和单例,可从任何地方使用。
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();
}
让我们考虑两个 QObjects
、senderObject
类型 SenderObject
和 receiverObject
类型 ReceiverObject
的场景。 senderObject
已在工作线程上创建,而 receiverObject
已在主线程上创建。现在让我们假设 SenderObject
有一个信号 somethingsChanged
并且让我们考虑以下代码片段:
片段 1:
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();
}
现在让我们考虑以下代码片段:
片段 2:
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();
}
Snippet2 中的 lambda 是否也会在主线程上执行,因为 lambda 已在主线程上声明,还是会在与 senderObject
相同的线程中执行?
这是我们的 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;
};
由于没有 QObject::connect
的重载需要一个 lambda 和一个 Qt
连接类型参数,Snippet2 将在发送者的线程中执行,它是一个工作线程。
为了强制 lambda 在主线程上执行,这里有一个解决方法:
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();
}
由于new QObject
是在主线程上调用的,lambda也会在主线程上执行。
或者,如果我们不喜欢看到 new
,这将起作用:
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();
}
或者,更好的解决方案是使用 qApp
,它是应用程序的实例和单例,可从任何地方使用。
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();
}