信号和槽的混淆行为取决于连接类型
Confusing behaviour of signals and slots depending on type of connection
我有以下片段
#include <QObject>
#include <QtConcurrent>
class Foo : public QObject {
Q_OBJECT
public:
explicit Foo(QObject *parent = nullptr) : QObject(parent) {
connect(this, &Foo::signal, this, &Foo::slot, ConnectionType);
}
void startBlockingMap() {
qDebug("startBlockingMap");
slot_counter = 0;
std::atomic_int signal_counter = 0;
QtConcurrent::blockingMap(nums, [&](auto &&num) {
++signal_counter;
emit signal();
});
qDebug("result: %d signals, %d slots", int(signal_counter), int(slot_counter));
slot_counter = 0;
}
public slots:
void slot() { ++slot_counter; }
signals:
void signal();
private:
std::atomic_int slot_counter = 0;
std::vector<int> nums{1, 2, 5, 8};
};
#include "main.moc"
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Foo *foo = new Foo(&app);
QTimer::singleShot(10, foo, [foo, &app]() {
foo->startBlockingMap();
app.quit();
});
return app.exec();
}
它根据传递给 connect
的连接类型产生不同的结果。
当ConnectionType
为Qt::DirectConnection
时输出为
startBlockingMap
result: 4 signals, 4 slots
说清楚了。
当ConnectionType
为Qt::QueuedConnection
时输出为
startBlockingMap
result: 4 signals, 0 slots
这不是。我以为,slots 会在 startBlockingMap
完成后执行,但根本没有执行。为什么?发生了什么事?
最后,ConnectionType
为 Qt::AutoConnection
的结果令人惊讶。我希望它们与 Qt::DirectConnection
或 Qt::QueuedConnection
(as documentation states) 相同,但它们不同:
startBlockingMap
result: 4 signals, x slots
其中 x
从 0 到 4 不等,具体取决于……某事。显然,存在一些数据竞争(?)。我不知道。
为什么插槽不执行 Qt::QueuedConnection
?
为什么连接类型为 Qt::AutoConnection
时的输出与连接类型为直接 和 时的输出不同?为什么这么随意?
编辑:
在 的帮助下,我看到要在 blockingMap
之后立即执行通过排队连接连接的插槽,应该通过调用 qApp->processEvents()
.
显式继续事件循环
Which is not. I thought, slots would be executed after maps are finished, but they are not executed at all. Why? What happened?
当控件返回到事件循环时,槽会被执行,但是这里 startBlockingMap
函数是从事件循环中调用的,所以当 startBlockingMap
函数 returns 并且控件返回到事件循环。
Why output when connection type is Qt::AutoConnection differs from output when connection type is direct and when it is queued? Why is it so random?
blockingMap 函数使用不同的线程来调用您的 lambda,有时是来自线程池的线程,有时是执行 blockingMap 函数的线程(这里是 'main' 线程)。您可以通过将行 qDebug() << this->thread() << ' ' << QThread::currentThread();
添加到 lambda 中来检查。现在 emit slot()
有时会从一个不是对象所有者的函数中执行,因此信号会排队,有时会从作为对象所有者的 'main'-thread 中执行,因此插槽会得到直接执行,可以在控制台看到增加。
我有以下片段
#include <QObject>
#include <QtConcurrent>
class Foo : public QObject {
Q_OBJECT
public:
explicit Foo(QObject *parent = nullptr) : QObject(parent) {
connect(this, &Foo::signal, this, &Foo::slot, ConnectionType);
}
void startBlockingMap() {
qDebug("startBlockingMap");
slot_counter = 0;
std::atomic_int signal_counter = 0;
QtConcurrent::blockingMap(nums, [&](auto &&num) {
++signal_counter;
emit signal();
});
qDebug("result: %d signals, %d slots", int(signal_counter), int(slot_counter));
slot_counter = 0;
}
public slots:
void slot() { ++slot_counter; }
signals:
void signal();
private:
std::atomic_int slot_counter = 0;
std::vector<int> nums{1, 2, 5, 8};
};
#include "main.moc"
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
Foo *foo = new Foo(&app);
QTimer::singleShot(10, foo, [foo, &app]() {
foo->startBlockingMap();
app.quit();
});
return app.exec();
}
它根据传递给 connect
的连接类型产生不同的结果。
当ConnectionType
为Qt::DirectConnection
时输出为
startBlockingMap
result: 4 signals, 4 slots
说清楚了。
当ConnectionType
为Qt::QueuedConnection
时输出为
startBlockingMap
result: 4 signals, 0 slots
这不是。我以为,slots 会在 startBlockingMap
完成后执行,但根本没有执行。为什么?发生了什么事?
最后,ConnectionType
为 Qt::AutoConnection
的结果令人惊讶。我希望它们与 Qt::DirectConnection
或 Qt::QueuedConnection
(as documentation states) 相同,但它们不同:
startBlockingMap
result: 4 signals, x slots
其中 x
从 0 到 4 不等,具体取决于……某事。显然,存在一些数据竞争(?)。我不知道。
为什么插槽不执行 Qt::QueuedConnection
?
为什么连接类型为 Qt::AutoConnection
时的输出与连接类型为直接 和 时的输出不同?为什么这么随意?
编辑:
在 blockingMap
之后立即执行通过排队连接连接的插槽,应该通过调用 qApp->processEvents()
.
Which is not. I thought, slots would be executed after maps are finished, but they are not executed at all. Why? What happened?
当控件返回到事件循环时,槽会被执行,但是这里 startBlockingMap
函数是从事件循环中调用的,所以当 startBlockingMap
函数 returns 并且控件返回到事件循环。
Why output when connection type is Qt::AutoConnection differs from output when connection type is direct and when it is queued? Why is it so random?
blockingMap 函数使用不同的线程来调用您的 lambda,有时是来自线程池的线程,有时是执行 blockingMap 函数的线程(这里是 'main' 线程)。您可以通过将行 qDebug() << this->thread() << ' ' << QThread::currentThread();
添加到 lambda 中来检查。现在 emit slot()
有时会从一个不是对象所有者的函数中执行,因此信号会排队,有时会从作为对象所有者的 'main'-thread 中执行,因此插槽会得到直接执行,可以在控制台看到增加。