简体   繁体   English

从Qt中的多个线程绘制

[英]Drawing from multiple threads in Qt

I'm writing a program in Qt, which runs 10 worker threads which calculate the trajectory of an object in space. 我正在Qt中编写一个程序,它运行10个工作线程来计算空间中物体的轨迹。 They also have to draw the path of the object. 他们还必须画出物体的路径。 I have a "Body" class deriving QGraphicsEllipseItem and it has a QPainterPath in it. 我有一个“Body”类派生QGraphicsEllipseItem,它有一个QPainterPath。 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). 模拟在一个单独的线程中运行(使用moveToThread完成,而不是通过继承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). 当所有线程都已完成时,我想绘制路径(我通过调用“Body”中的方法来实现它,该方法在其draw方法中启用路径绘制)。

Unfortunately I get ASSERT errors : 不幸的是我得到了ASSERT错误:

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

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 5.0

Generally speaking, with Qt you can't do any GUI operations outside of the GUI thread (ie the thread that is executing QApplication::exec(), which is typically the main() thread). 一般来说,使用Qt,你不能在GUI线程之外进行任何GUI操作(即执行QApplication :: exec()的线程,通常是main()线程)。

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. 因此,如果您有多个线程来操纵QGraphicsItems(特别是当前属于QGraphicsScene的QGraphicsItems),这可能是您断言失败的原因。 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. 也就是说,当Qt GUI线程正在进行窗口刷新时,它正在从各种QGraphicsItem对象中读取数据作为其计算的一部分,并且它期望QGraphicsItem在刷新操作的持续时间内保持不变。 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). 如果在执行刷新例程时(由另一个线程)更改了QGraphicsItem,则主线程进行的计算可能会变得错误/损坏,并且偶尔会导致断言失败(和/或其他不需要的行为)。

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. 如果你真的需要使用多个线程,那么你可能需要做的就是让线程在他们自己的私有数据结构上进行所有计算,这些结构是Qt GUI线程无法访问的。 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()). 然后,当线程计算了它们的结果时,它们应该将结果发送回Qt GUI线程(通过排队连接或QApplication :: postEvent())。 The GUI thread can then look at the results and use them to update the QGraphicsItems, etc; 然后GUI线程可以查看结果并使用它们来更新QGraphicsItems等; this will be "safe" because this update can't happen in the middle of a window update. 这将是“安全的”,因为此更新不会在窗口更新过程中发生。

If that sounds like too much work, then you might consider just doing everything in the GUI thread; 如果这听起来太多了,那么你可能会考虑在GUI线程中做所有事情; it will be much easier and simpler to make everything work reliably that way. 通过这种方式使一切工作变得更加容易和简单。

As mentioned by Jeremy, Qt rendering must be done on the main thread. 正如Jeremy所提到的,Qt渲染必须在主线程上完成。

While you could move it all to the main thread, you've likely chosen to create separate ones for efficiency, especially as collision detection can be processor intensive. 虽然您可以将它全部移动到主线程,但您可能已经选择创建单独的线程以提高效率,尤其是因为冲突检测可能是处理器密集型的。 The best way to handle this is to split the modelling of the objects and their physics from their rendering, as you would in a Model / View / Controller pattern. 处理此问题的最佳方法是将对象及其物理的建模与渲染分开,就像在模型/视图/控制器模式中一样。

Create representations of the body instances that are not derived from any QGraphicsItem/Objects. 创建不是从任何QGraphicsItem / Objects派生的正文实例的表示。 These can then do their calculations on separate threads and have signals to graphics objects that are running in the main thread, which updates each body instance's graphic representation, allowing real-time rendering of the trajectories. 然后,这些可以在单独的线程上进行计算,并向主线程中运行的图形对象发出信号,这些图形对象更新每个主体实例的图形表示,从而允许实时渲染轨迹。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM