QtConcurrent を使用して重い背景画像処理を行っていますが、画像の一部が徐々に更新されている間に画像を表示したいと考えています。画像の各行は個別に計算され、ファンクタに渡されます。
完全な画像を計算するには、QtConcurrent に渡すアイテムのシーケンスをマップし、計算が完了すると各行が信号を発します。
クラス Worker のインスタンス化は次のとおりです。
//living in the main(gui) thread !
Worker::Worker(VideoEngine* engine):_engine(engine){
_watcher = new QFutureWatcher<bool>;
_watcher->setPendingResultsLimit(200);
connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
進行状況を報告するスロットは次のとおりです。
void Worker::onProgressUpdate(int i){
if(i < (int)_rows.size() && i%10==0){
cout << " index = " << i << " y = "<< _rows[i] << endl;
_engine->checkAndDisplayProgress(_rows[i],i);
}
}
今の使い方:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}
すべてのシグナルが発行されますが、スロット onProgressUpdate は Qtconcurrent::mapped がシーケンス内のすべてのアイテムで完了した場合にのみ呼び出されます。
実行すると、シーケンスの処理中に大きな遅延が発生し、その後すべてのスロットが順番に実行されます。
すべてのタイプのシグナル/スロット接続を試しましたが、どれもこの動作を変更しませんでした。
どんな手掛かり ?
++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ Shf 提案後の編集 +++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++
呼び出しは今までメイン (gui) スレッドで行われていました。呼び出しを次のように変更しました:
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));
別のスレッドで実行されるようになったため_computeTreeForFrame
、QtConcurrent::mapped への呼び出しを次のように変更しました。
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
これにより、以前とまったく同じ動作が発生します。
++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ マレク R 提案後の編集 ++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++
わかりましたので、テストを行いました。ここに私が観察したものがあります:
QtConcurrent::map :
- 信号を出さない
resultReadyAt(int)
QtConcurrent::mapped
- 終了
resultReadyAt(int)
時のみ出力
map 関数の呼び出しが別のスレッドで行われても、同じ動作が発生します。
progressValueChanged(int)
Qt progressDialog の例が示すように、シグナルも試しました。信号は、画像の 2 行 (最初と最後)progressValueChanged(int)
に対してのみ発せられます。これは、Qt の進行状況ダイアログの例ではスムーズに出力されるため、非常に奇妙です。
メイン スレッドとは別のスレッドでマップ関数を起動するように Qt の例を少し変更しましたが、その場合でも問題なく動作します。
問題は別の場所から発生する必要があります。
GUI イベント ループが予期しないことを行っている可能性があります。私には何の手がかりもありません。
QtConcurrent::mappedReduced を試して、結果を報告します:-)
++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ QtConcurrent::mappedReduced を試した後の編集 +++++ ++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++
「マップ」機能が完了した場合にのみ機能せず、「縮小」機能を呼び出します。つまり、以前のシグナル/スロットメカニズムと同じことを行います。
私は今、可能性が少なくなりつつあります
++++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ 編集 Qt の進行状況ダイアログに近いソリューションに戻りました例 ++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++++++++++
Qt の例と同じ動作が得られない場合は、何かが間違っているに違いありません。
コードは次のとおりです。
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
_watcher = new QFutureWatcher<void>;
_watcher->setPendingResultsLimit(200);
connect(_watcher,SIGNAL(progressValueChanged(int)), _engine,
SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}
computeTreeForFrame の呼び出し...
...
_worker->computeTreeForFrame();
...
この呼び出しはslot で行われます。
前に述べたように、行 0 と最後の行のシグナルを送信しますが、他には何も送信しません。
これは Qt の例とまったく同じではないでしょうか?