0

OS-X 10.8.4 を搭載した Mac で Qt 5.1 と QtQuick 2.0 を実行しています。

ファイル I/O 操作でイベント ループをブロックしているため、Qt-QML GUI が応答しなくなります。これを解決するための通常のアプローチは、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) ...
}

これはあまり現実的ではありませんが、以下で遭遇した問題を説明するための簡単なスケッチとして役立ちます。

追加の「datamodel.h」クラス内に QtConcurrent::blockingMapped() をカプセル化しようとすると、問題が発生します。

#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 を使用していませ)。:

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

どうやら、ラムダ式を持つ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 に答える