2017-03-26 4 views
0

私は永遠にフォルダを監視し、マルチスレッド処理のために新しいファイルをキューに追加するアプリケーションを作成しようとしています。QtConcurrent :: mapによって操作されているQStringListにどのように追加できますか?

これは私が持っているものです。

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 
    QDir dir("/home/boat/Programming/"); 
    QStringList folders = QStringList() << "/home/boat/Programming/"; 
    QStringList filters = QStringList() << "*.boat"; 
    QStringList boatFileNames = dir.entryList(filters); 

    /* Start Threading | Files from list are deleted on completion */ 
    QtConcurrent::map(boatFileNames, &someFunction); 

    /* Monitor folder for new files to add to queue */ 
    QFileSystemWatcher fsw(folders); 
    QObject::connect(&fsw,&QFileSystemWatcher::directoryChanged,[&](){ 
      ???? 
    }); 
    a.exec(); 
} 

私は、スレッドの安全性のために確保する必要がある唯一の事は、私は同じ関数の2つのスレッドによって操作されている一つのファイルを持つことができないということです。

  1. 待ちマップが終了するまで、ファイル用のフォルダを再度確認しQStringListを再増殖し、マップを再開:

    私はそれを見る方法、私は2つのオプション、私が行う方法を知っているどちらを持っています。

  2. 地図を送るQStringListに追加します。マップは決して閉じず、キューにアイテムを追加し続けるだけで関数を操作します。

これらのいずれかが可能ですか、これについては別の方法がありますか?

答えて

1

QStringListに追加するには、 QtConcurrent :: map?永遠にフォルダを監視し、マルチスレッド処理のために新しいファイルをキューに追加するアプリケーションを作成しようとしています。

mutexで保護された単純なスタックまたはキューのようなコンテナでタスクを実装できるため、QtConcurrent::mapも使用しません。

すべてのワーカー(コンシューマ)スレッドを自分の信号に接続します。たとえば、void MyClass:: newFileAvailable()です。

移入しvoid QFileSystemWatcher::directoryChanged(const QString &path)信号を作成し、キューのような構造(またはあなたはそれがスタックなどを行うことができます):だから

class FilePathQueue 
{ 
    void push(const QString& path) 
    { 
     QMutexLocker lock(&mutex); 
     list.push_back(path); 
    } 
    QString pop() 
    { 
     QMutexLocker lock(&mutex); 
     if (list.isEmpty()) 
     return QString(); 
     QString ret = list.front(); 
     list.pop_front(); 
     return ret; 
    } 
private: 
    QMutex mutex; 
    QStringList list; 
}; 

は、すべてのワーカースレッドがnewFileAvailable()信号に加入しなければならないし、新しいファイルパスを消費しますFilePathQueue::pop()を介して利用可能なアイテムが残っているかどうかを確認します。これはQtのシンプルで言う、と非常に管理して行われる

// the worker thread supposed to be running in own thread 
// see QObject::moveToThread() 
class MyWorker : public QObject 
{ 
    public: 
     MyWorker(QObject* parent, FilePathQueue& list) : 
     QObject(parent), fileList(list) {} 
    /// 
    public slots: 
     void processNewFile() 
     { 
      QString path = fileList.pop(); 
      if (path.isEmpty()) return; 

      process(path); 
     } 

     void process(const QString& path); 
    private: 
     FilePathQueue& fileList; 
}; 

、いくつかの労働者あたり毎秒何千ものファイルの到着信号が、より多くの消費者以上と高い割合のため:

/* File path thread-safe container */ 
FilePathQueue fileList; 

/* Monitor folder for new files to add to queue */ 
QFileSystemWatcher fsw(folders); 
QObject::connect(&fsw, &QFileSystemWatcher::directoryChanged, 
    [&](const QString& path){ 
     fileList.push(path);  // push in new path 
     emit newFileAvailable(); // let workers know 
     // TODO: here we can have condition.notify_all() or notify_one() 
     // instead of signal emit for the higher performance 
}); 

// launch new workers 
for(int n=0; n<8; ++n) 
{ 
    Worker* worker = new Worker(this, fileList); // create worker and 
    worker->start(); // starts own thread etc. 

    connect(this, &MyClass::newFileAvailable,  // connect it to new 
      worker, &MyWorker::processNewFile); // file signal 
} 

ワーカークラスリアルタイムパフォーマンスシステムQWaitCondition :: wait()は、ロジックに応じて、ワーカースレッド側でQWaitCondition::notify_one()またはnotify_all()を実行する必要があります。そのロジックを実装するために、より精巧なワーカースレッドの例を提示する必要があります。

関連する問題