首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QtConcurrent::块映射与QtConcurrent::map和waitForFinished

QtConcurrent::块映射与QtConcurrent::map和waitForFinished
EN

Stack Overflow用户
提问于 2018-12-30 15:16:51
回答 2查看 1.1K关注 0票数 1

Qt文档显示了关于QtConcurrent::块映射的以下内容

注意:此函数将被阻塞,直到序列中的所有项都已被处理。

QtConcurrent::map的文档在其他方面是相同的。另外,它返回QFuture<void>而不是void

QFuture的文档有以下说明:

waitForFinished()函数导致调用线程阻塞并等待计算完成,确保所有结果都可用。

因此,我认为QtConcurrent::blockingMap(seq, f)QtConcurrent::map(seq, f).waitForFinished()是完全相同的。然而,事实并非如此。

代码语言:javascript
复制
#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();
}

输出是

代码语言:javascript
复制
startMapWithWaiting
result: 4 signals, 4 slots
startBlockingMap
result: 4 signals, x slots

其中x从0到4不等,这取决于…某物。这很让人困惑。

我想知道这两种方式之间有什么区别,以及我如何误读文档。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-01-01 10:02:02

blockingMap保证在主线程(应用程序“生命”)中不会执行其他任何操作。因此,它可能与池一起使用主线程,而QtConcurrent::map不能在主线程中执行lambda。这就是导致不同结果的原因。实际上,x是在主线程中执行lambda的次数。原因如下:

Qt::AutoConnection在发出信号的同一个线程中的接收方lives立即调用信号(在我的例子中,在主线程中),因此slot_counter被更新。在另一个线程中接收lives时,调用时隙将排队,并将在startBlockingMapstartMapWithWaiting完成时进行处理。要立即处理它们,可以将qApp->processEvents()称为钨建议

票数 1
EN

Stack Overflow用户

发布于 2018-12-31 14:40:50

这两种方法的工作方式相同:所有lambda函数都被终止,发出了4个信号。示例中调用的插槽的差异取决于emit signal()的工作方式。由于程序使用Qt::AutoConnection作为信号/插槽:

  • 如果目标线程(创建Foo的主线程)与当前线程(由全局ThreadPool控制的池线程)不相同,则事件将放在事件队列中,否则,插槽将直接执行(与Qt::DirectConnection相同)。

使用相同的示例,可以得到不同的结果(x时隙)。这取决于全局线程池如何管理其线程。在我的配置中,输出是:

代码语言:javascript
复制
    startMapWithWaiting
    result : 4 signals, 0 slots
    startBlockingMap
    result : 4 signals, 4 slots

为了获得相同的结果,我们可以使用Qt::DirectConnection代替Qt::AutoConnection,或者在打印结果之前调整QApplication::processEvent():

代码语言:javascript
复制
    QApplication::processEvents(); //<-- force slot() to be processed.
    qDebug("result blocking : %d signals, %d slots", int(signal_counter), int(slot_counter));
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53978796

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档