5

Qt でプログラムを作成しています。このプログラムは、空間内のオブジェクトの軌跡を計算する 10 個のワーカー スレッドを実行します。また、オブジェクトのパスを描画する必要があります。QGraphicsEllipseItem を派生する「Body」クラスがあり、その中に QPainterPath があります。「Simulation」クラスは、世界の障害物のリストと、シミュレートするボディを受け取り、ボディが何かに衝突するまで実行します。シミュレーションは別のスレッドで実行されます (QThread をサブクラス化するのではなく、moveToThread で実行します)。ボディが衝突すると、シミュレーションは終了したことを示す信号を発します。すべてのスレッドが終了したら、パスを描画したいと思います (描画メソッドでパスの描画を有効にする「ボディ」のメソッドを呼び出して実行します)。

残念ながら、私は ASSERT エラーが発生します:

ASSERT: "!unindexedItems.contains(item)" in file graphicsview\qgraphicsscenebsptreeindex.cpp, line 364

それらは一見ランダムに発生します。さまざまな接続タイプを試しましたが、結果はありませんでした。
スレッドをループで開始しています。
私はQt 5.0を使用しています

4

2 に答える 2

11

一般的に言えば、Qt では、GUI スレッド (つまり、QApplication::exec() を実行しているスレッド、通常は main() スレッド) の外で GUI 操作を行うことはできません。

そのため、QGraphicsItems (特に現在 QGraphicsScene の一部である QGraphicsItems) を操作する複数のスレッドがある場合、それがアサーションの失敗の原因である可能性があります。つまり、Qt GUI スレッドがウィンドウの更新を行っているとき、計算の一部としてさまざまな QGraphicsItem オブジェクトからデータを読み取り、QGraphicsItems が更新操作の間一定のままであることを期待します。更新ルーチンの実行中に QGraphicsItem が (別のスレッドによって) 変更された場合、メイン スレッドによって行われた計算が間違ったり破損したりする可能性があり、アサーションの失敗 (および/またはその他の望ましくない動作) が発生することがあります。

本当に複数のスレッドを使用する必要がある場合は、Qt GUI スレッドがアクセスできない独自のプライベート データ構造でスレッドにすべての計算を行わせる必要があります。次に、スレッドが結果を計算したら、結果を Qt GUI スレッドに送り返す必要があります (キュー接続または QApplication::postEvent() を介して)。GUI スレッドは結果を見て、それらを使用して QGraphicsItems などを更新できます。この更新はウィンドウの更新中に発生することはないため、これは「安全」です。

それが面倒だと思われる場合は、GUI スレッドですべてを実行することを検討してください。すべてをそのように確実に機能させる方がはるかに簡単で簡単です。

于 2013-04-28T03:21:19.890 に答える
2

Jeremy が述べたように、Qt のレンダリングはメイン スレッドで行う必要があります。

すべてをメイン スレッドに移動することもできますが、特に衝突検出はプロセッサを集中的に使用する可能性があるため、効率のために別のスレッドを作成することを選択した可能性があります。これを処理する最善の方法は、モデル/ビュー/コントローラー パターンの場合と同様に、オブジェクトのモデリングとその物理をレンダリングから分離することです。

QGraphicsItem/Objects から派生していないボディ インスタンスの表現を作成します。次に、これらは別々のスレッドで計算を行い、メイン スレッドで実行されているグラフィックス オブジェクトに信号を送信します。これにより、各ボディ インスタンスのグラフィック表現が更新され、軌道のリアルタイム レンダリングが可能になります。

于 2013-04-30T08:13:54.383 に答える