从 Qt 中的多个线程绘图
我正在用 Qt 编写一个程序,它运行 10 个工作线程来计算对象在空间中的轨迹.他们还必须绘制对象的路径.我有一个派生 QGraphicsEllipseItem 的Body"类,其中有一个 QPainterPath.模拟"类获取世界中的障碍物列表,以及要模拟的身体并运行直到身体与某物碰撞.模拟在单独的线程中运行(使用 moveToThread 完成,而不是通过子类化 QThread).当身体发生碰撞时,模拟会发出一个信号,表示它已经完成.当所有线程都完成后,我想绘制路径(我通过调用Body"中的一个方法来绘制路径,该方法在其 draw 方法中启用路径绘制).
I'm writing a program in Qt, which runs 10 worker threads which calculate the trajectory of an object in space. They also have to draw the path of the object. I have a "Body" class deriving QGraphicsEllipseItem and it has a QPainterPath in it. The "Simulation" class takes a list of obstacles in the world, and the body to simulate and runs until the body collides with something. Simulation runs in a separate thread ( done with moveToThread, not by subclassing QThread). When the body collides, the Simulation emits a signal saying that it finished. When all threads have finished I'd like to draw the paths (I do it by invoking a method in "Body" which enables path drawing in its draw method).
不幸的是,我收到了 ASSERT 错误:
Unfortunately I get ASSERT errors :
ASSERT: "!unindexedItems.contains(item)" in file graphicsviewqgraphicsscenebsptreeindex.cpp, line 364
它们似乎是随机发生的.我尝试了不同的连接类型,但没有结果.
我正在循环启动线程.
我正在使用 Qt 5.0
They happen seemingly randomly. I've tried different connection types, to no result.
I'm starting the threads in a loop.
I'm using Qt 5.0
推荐答案
一般来说,使用 Qt 你不能在 GUI 线程(即执行 QApplication::exec() 的线程之外)做任何 GUI 操作,这通常是 main() 线程).
Generally speaking, with Qt you can't do any GUI operations outside of the GUI thread (i.e. the thread that is executing QApplication::exec(), which is typically the main() thread).
因此,如果您有多个线程在操作 QGraphicsItems(尤其是当前属于 QGraphicsScene 的 QGraphicsItems),这很可能是您的断言失败的原因.也就是说,当 Qt GUI 线程进行窗口刷新时,它正在从各种 QGraphicsItem 对象中读取数据作为其计算的一部分,并且它希望 QGraphicsItems 在刷新操作期间保持不变.如果在执行刷新例程时(由另一个线程)更改了 QGraphicsItem,则主线程进行的计算可能会出错/损坏,并且偶尔会导致断言失败(和/或其他不需要的行为).
So if you have multiple threads manipulating QGraphicsItems (especially QGraphicsItems that are currently part of a QGraphicsScene), that is likely the cause of your assertion failures. That is, when the Qt GUI thread is doing its window refresh, it is reading data from the various QGraphicsItem objects as part of its calculations, and it expects the QGraphicsItems to remain constant for the duration of the refresh operation. If a QGraphicsItem is changed (by another thread) while the refresh routine is executing, then the calculations made by the main thread can become wrong/corrupted, and that occasionally causes an assertion failure (and/or other unwanted behaviors).
如果您真的需要使用多个线程,您可能需要做的是让线程在 Qt GUI 线程无法访问的私有数据结构上进行所有计算.然后当线程计算出它们的结果时,它们应该将结果发送回 Qt GUI 线程(通过排队连接或 QApplication::postEvent()).然后 GUI 线程可以查看结果并使用它们来更新 QGraphicsItems 等;这将是安全的",因为此更新不能在窗口更新过程中发生.
If you really need to use multiple threads, what you'll probably need to do is have the threads do all their calculations on their own private data structures that the Qt GUI thread has no access to. Then when the threads have computed their results, they should send the results back to the Qt GUI thread (via queued connection or QApplication::postEvent()). The GUI thread can then look at the results and use them to update the QGraphicsItems, etc; this will be "safe" because this update can't happen in the middle of a window update.
如果这听起来工作量太大,那么您可以考虑只在 GUI 线程中做所有事情;以这种方式使一切可靠地工作会变得更加容易和简单.
If that sounds like too much work, then you might consider just doing everything in the GUI thread; it will be much easier and simpler to make everything work reliably that way.
相关文章