QtConcurrent::blockingMap vs QtConcurrent::map and waitForFi
QtConcurrent::blockingMap vs QtConcurrent::map and waitForFinished
Qt文档对QtConcurrent::blockingMap有如下说明:
注意:此功能将阻止,直到处理完序列中的所有项目。
QtConcurrent::map 的文档在其他方面是相同的。此外,它还返回QFuture<void>
而不是void
。
QFuture 的文档有以下注释:
waitForDone() 函数使调用线程阻塞并等待计算完成,从而确保所有结果都可用。
因此,我希望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 不等,具体取决于...东西。这令人困惑。
想知道这两种方式之间有什么区别以及我是如何误读文档的。
这两种方法的工作方式相同:所有 lambda 函数在发出 4 个信号时终止。示例中调用的插槽的差异取决于emit signal()
的工作方式。由于程序用于信号/插槽Qt::AutoConnection
:
- 如果目标线程(创建Foo的主线程)与当前线程(池线程,由全局ThreadPool控制)不同,则该事件将被放入事件队列中,否则,该插槽将直接执行(与
Qt::DirectConnection
相同)。
使用所示的相同示例可以获得不同的结果(x 插槽)。这取决于全局线程池如何管理其线程。在我的配置中,输出是:
startMapWithWaiting
result : 4 signals, 0 slots
startBlockingMap
result : 4 signals, 4 slots
为了得到相同的结果,我们可以在打印结果之前使用 Qt::D irectConnection 而不是 Qt::AutoConnection 或调整 QApplication::p rocessEvent():
QApplication::processEvents(); //<-- force slot() to be processed.
qDebug("result blocking : %d signals, %d slots", int(signal_counter), int(slot_counter));
blockingMap
保证不会在主线程(应用程序"生活"的地方)中执行任何其他操作。因此,它可能使用主线程和池线程,而QtConcurrent::map
无法在主线程中执行 lambda。这就是导致不同结果的原因。实际上,x
是在主线程中执行 lambda 的次数。原因如下:
当接收器lives
发出信号的同一线程中(在我的例子中,在主线程中)时,Qt::AutoConnection
会立即调用信号,因此slot_counter
会更新。当接收方lives
另一个线程时,调用槽将排队,并将在startBlockingMap
或startMapWithWaiting
完成时进行处理。为了立即处理它们,可以按照tungit的建议调用qApp->processEvents()
。
- 为什么我在代码厨师的 CMPRSS 问题中得到 WA(错误答案)?
- QtConcurrent::mapped not compiling
- QtConcurrent - 在发布到 UI 线程的数千个结果中保持 GUI 响应
- C++Qt QtConcurrent::filtered从std::shared_ptr的QVector减少
- 使用 QtConcurrent::run() 修改成员变量?
- 如何在QtConcurrent::run中启动QTimer或为什么QVector<QTimer*>不起作用
- 如何将字符串数组传递到 QtConcurrent::run 中?
- 让 QtConcurrent 中的 QTimer 正常工作
- C2064:术语未评估为1个参数qtConcurrent :: map的函数
- 我已经通过了该问题的所有测试用例,甚至是Udebugg上的所有测试用例,并且仍然在UVA在线法官上获得了WA裁决
- 在 c++11 模式下使用 QtConcurrent::run with move only 参数
- 使QTConcurrent ::映射与Lambdas一起工作
- 带地图的解决方案给了空调,unordered_map的解决方案给了WA.为什么
- 如何添加到由QtConcurrent::map操作的QStringList中?
- Qt - 如何将 QtConcurrent 和 QThreadPool 组合成 QProgressBar?
- 为什么我在SPOJ上为Buglife获得WA
- QtConcurrent::run 是否可以与指向对象的智能指针一起使用
- QtConcurrent::blockingMap vs QtConcurrent::map and waitForFi
- 在课堂中使用QTConcurrent :: mappedReduce
- 如何使用QTConcurrent ::运行过载函数