0

我在装有 OS-X 10.8.4 的 Mac 上运行 Qt 5.1 和 QtQuick 2.0。

我的 Qt-QML GUI 变得无响应,因为我用文件 I/O 操作阻塞了事件循环。解决它的常用方法是使用Will Bickford在此处讨论的多个线程。

为此,我正在尝试使用:

QtConcurrent::blockingMapped() 

这比使用显式 QFuture 对象更简单。我一直在阅读Qt 文档很酷的示例,并获得了以下代码(仿照此示例):

// NOTE: this all seems to work:
#include <QList>
#include <iostream>
#include "dataobject.h"
#include <QtConcurrent/QtConcurrentMap>

DataObject load(const QString &file) {
    std::cout << "File I/O in thread = " << QThread::currentThread() << std::endl;
    return DataObject anObject(file);
}

int main(int argc, char *argv[])
{
    ...

    // Create a list of filenames:
    int count = 5;
    QList<QString> allFiles;
    for (int i = 0; i < count; i++) {
        allFiles.append(QString("aFileName"));
    }
    std::cout << "# of files = " << allFiles.size() << std::endl;

    QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles,load);
    std::cout << "# of objects = " << allTheDataObjects.size() << std::endl;

    ...
}

以下是 DataObject 的头文件和实现文件:

#include <QString>
class DataObject
{
public:
    DataObject();
    DataObject(QString filename);
    QString theFileName;
};

#include "dataobject.h"

DataObject::DataObject() {
    theFileName = QString("no file");
}
DataObject::DataObject(QString filename) {
    theFileName = filename;
    //...
    // Do file I/O stuff (slow) ...
}

这不是很现实,但可以作为一个简单的草图来说明我在下面遇到的问题。

当我尝试将 QtConcurrent::blockingMapped() 封装在一个额外的“datamodel.h”类中时,就会出现问题:

#include "dataobject.h"
class DataModel
{
public:
    DataModel();
    void runConcurrent();
    DataObject load(const QString& fileList);
};

#include "datamodel.h"
#include <QtConcurrent/QtConcurrentMap>
#include <iostream>

DataModel::DataModel() {}
DataObject DataModel::load(const QString &file) {
    std::cout << "File I/O in thread = " << QThread::currentThread() << std::endl;
    return DataObject anObject(file);
}
void DataModel::runConcurrent() {
    // Create a list of filenames:
    int count = 5;
    QList<QString> allFiles;
    for (int i = 0; i < count; i++)
        allFiles.append(QString("dummyFileName"));
    QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, this->load);
    std::cout << "# of objects = " << allTheDataObjects.size() << std::endl;
}

然后 main() 变成了(注意我也把 load() 方法移到了 DataModel 类中):

#include <QList>
#include <iostream>
#include "dataobject.h"
#include "datamodel.h"
#include <QtConcurrent/QtConcurrentMap>

int main(int argc, char *argv[])
{
    ...

    DataModel theModel;
    theModel.runConcurrent();

    ...
}

但是现在有一个编译器错误:

datamodel.cpp: error: reference to non-static member function must be called:
QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, this->load);

我无法通过初始化 DataObject 或 DataModel 实例来修复编译器错误(以便可以看到非静态成员函数),并且不确定还有什么可以尝试的。

接下来,我怀疑这可能是由于设置 QtConcurrent 参数时“函子”绑定的问题(我没有安装 boost,所以没有使用boost::bind)所以我尝试了Mat 的建议,即通过替换使用 C++ 11 lambdas :

this->load

和:

[this](const QString& file){load(file);}

给出代码:

QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, 
                                       [this](const QString& file){load(file);});

现在我不再收到非静态成员错误,而是出现了一个新错误(指向上面的行):

datamodel.cpp: error: expected expression:

我真的在这个问题上陷入了困境,这可能是一个简单的错误,但我很难把它整理出来。

有人可以帮忙吗?

4

2 回答 2

0

显然您不使用具有 lambda 表达式的 C++11。所以使用来自 STL 或 Boost 的绑定或创建函数对象。

QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, 
                                   std::bind1st(std::mem_fun(&DataModel::load), this));

好的,上面的解决方案不能与引用一起使用(知道错误)。定义函子(或使用 Boost::bind):

class LoadDataModel /*: public std::unary_function<QString, DataObject>*/ {
public:
    LoadDataModel(DataModel *p) : d(p) {}

    DataObject operator()(const QString &s) const {
        return d->load(s);
    }
private:
    DataModel *d;
}

QList<DataObject> allTheDataObjects = QtConcurrent::blockingMapped(allFiles, LoadDataModel(this));
于 2013-08-11T21:35:03.120 回答
0

好的,让它工作。

如果这可以使那些不想弄乱绑定或编写自己的“函子”的人受益(下面的方法更简单):

首先将 datamodel.h 文件中的静态类型用于“加载”功能:

static DataObject load(const QString& fileList);

这是因为可以调用 C++ 类的静态函数而无需实例化对象。

然后,在 datamodel.cpp 文件中,就是这么简单:

DataModel::load 

给:

QList<DataObject> allTheDataObjects = 
                      QtConcurrent::blockingMapped(allFiles, DataModel::load);

然后代码按预期运行。

于 2013-08-13T18:11:44.747 回答