Qt文档对QtConcurrent::blockingMap说了以下几点:
注意:此功能将阻塞,直到处理完序列中的所有项目为止。
QtConcurrent::map的文档在其他方面是相同的。还会返回QFuture<void>
而不是void
。
QFuture的文档具有以下说明:
waitForFinished()函数使调用线程阻塞并等待计算完成,以确保所有结果均可用。
因此,我希望QtConcurrent::blockingMap(seq, f)
与QtConcurrent::map(seq, f).waitForFinished()
相同。但是,不是。
#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, Qt::AutoConnection);
}
void startMapWithWaiting() {
qDebug("startMapWithWaiting");
slot_counter = 0;
std::atomic_int signal_counter = 0;
QtConcurrent::map(nums, [&](auto &&num) {
++signal_counter;
emit signal();
}).waitForFinished();
qDebug("result: %d signals, %d slots", int(signal_counter), int(slot_counter));
slot_counter = 0;
}
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->startMapWithWaiting();
foo->startBlockingMap();
app.quit();
});
return app.exec();
}
输出为
startMapWithWaiting
result: 4 signals, 4 slots
startBlockingMap
result: 4 signals, x slots
x
的范围从0到4,具体取决于……某些因素。这很令人困惑。
我想知道这两种方式之间有什么区别,以及我如何误读文档。
答案 0 :(得分:1)
两种方法的工作方式相同:所有的lambda函数都以发出的4个信号终止。示例中调用的插槽的不同取决于emit signal()
的工作方式。由于该程序将Qt::AutoConnection
用于信号/插槽:
Qt::DirectConnection
相同)。使用所示的相同示例,可以获得不同的结果(x个插槽)。这取决于全局线程池如何管理其线程。在我的配置中,输出为:
startMapWithWaiting
result : 4 signals, 0 slots
startBlockingMap
result : 4 signals, 4 slots
要获得相同的结果,我们可以在打印结果之前使用Qt :: DirectConnection代替Qt :: AutoConnection或调整QApplication :: processEvent():
QApplication::processEvents(); //<-- force slot() to be processed.
qDebug("result blocking : %d signals, %d slots", int(signal_counter), int(slot_counter));
答案 1 :(得分:0)
blockingMap
提供了保证在主线程(应用程序“存在”的地方)将不执行任何其他操作的保证。因此,它可能将主线程与池一起使用,而QtConcurrent::map
无法在主线程中执行lambda。这就是导致不同结果的原因。实际上,x
是在主线程中执行lambda的次数。原因如下:
Qt::AutoConnection
在同一线程中的接收方lives
发出信号后立即调用信号(在我的情况下,在主线程中),因此slot_counter
被更新。当接收方lives
在另一个线程中时,调用槽将排队,并且startBlockingMap
或startMapWithWaiting
完成时将对其进行处理。要立即处理它们,可以将qApp->processEvents()
称为tungit suggests。