2013-04-28 100 views
5

我在Qt中編寫了一個程序,該程序運行10個工作線程,該線程計算空間中對象的軌跡。他們也必須繪製物體的路徑。我有一個派生QGraphicsEllipseItem的「Body」類,它有一個QPainterPath。 「模擬」課程列出了世界上的障礙物,身體模擬並運行,直到身體碰撞某物。模擬在單獨的線程中運行(使用moveToThread完成,而不是通過繼承QThread)。當身體發生碰撞時,模擬發出一個信號說明它已完成。當所有線程都完成時,我想繪製路徑(我通過調用「Body」中的方法來執行此操作,該方法在其繪圖方法中啓用路徑繪製)。從Qt中的多個線程繪製

不幸的是,我得到ASSERT錯誤:

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

他們看似隨機發生。我試過不同的連接類型,但沒有結果。
我開始循環中的線程。
我正在使用Qt 5.0

回答

10

一般來說,使用Qt,您不能在GUI線程之外執行任何GUI操作(即執行QApplication :: exec()的線程,這通常是主要的)線程)。所以如果你有多個線程操縱QGraphicsItems(尤其是當前QGraphicsScene的一部分的QGraphicsItems),那很可能是你的斷言失敗的原因。也就是說,當Qt GUI線程正在進行窗口刷新時,它正在從各種QGraphicsItem對象讀取數據作爲其計算的一部分,並且期望QGraphicsItem在刷新操作期間保持不變。如果QGraphicsItem在執行刷新例程時被另一個線程更改,則主線程所做的計算可能會變得錯誤/損壞,並且偶爾會導致斷言失敗(和/或其他不需要的行爲)。

如果你確實需要使用多個線程,你可能會需要做的是線程做他們對Qt的圖形用戶界面線程有沒有訪問自己的私人數據結構中的所有計算。然後,當線程計算出結果時,他們應該將結果發送回Qt GUI線程(通過排隊連接或QApplication :: postEvent())。 GUI線程可以查看結果並使用它們來更新QGraphicsItems等;這將是「安全的」,因爲此更新不能在窗口更新中發生。

如果這聽起來像太多的工作,那麼你可以考慮只是做在GUI線程的一切;使所有事情都能夠可靠地工作將變得更加容易和簡單。

+0

「理想情況下,這些不會是Qt對象,儘管如果您非常小心,可能會使用某些Qt類」?有大量的類可以在GUI線程之外使用...有數字會很有趣,但我會說只有一小部分Qt不能在GUI線程之外使用。 – 2013-04-28 11:16:48

+0

@LucaCarlon我的觀點是,如果你使用Qt類,你需要驗證它們是否安全使用,而如果你使用非Qt類,幾乎可以保證它不會有任何非明顯的與Qt GUI線程的交互。 – 2013-04-28 17:12:18

+0

有關Qt和多線程的一些指導方針在這裏:http://www.informit.com/articles/article.aspx?p=1405551&seqNum=4 – 2013-04-28 17:16:49

3

正如傑里米提到的那樣,Qt的渲染必須在主線程上完成。

雖然你可以把它全部移動到主線程,您可能已經選擇創建效率獨立的人,尤其是碰撞檢測可以是處理器密集型的。處理這個問題的最好方法是將對象的建模和它們的物理模型從渲染中分離出來,就像在模型/視圖/控制器模式中一樣。

創建不是從任何的QGraphicsItem /對象導出的體實例的表示。然後,它們可以在單獨的線程上進行計算,並向主線程中運行的圖形對象發送信號,該線程更新每個主體實例的圖形表示,從而實現軌跡的實時渲染。