Qt物理场景多线程

9
我有一个QGraphicsScene,里面有大约1000个QGraphicsItems,它们实际上是物理项。每一帧它们都会推进,检查碰撞并解决碰撞,除此之外还有其他操作。我真的很想将物理多线程化。
据我了解QGraphics类不是线程安全的,这意味着只能从主线程调用它们。这是否强制我使用信号/槽机制将最终的项属性(x,y,旋转)每一帧发送到主线程,然后使用主线程方法来实际更新QGraphicsItems?或者有更简单的方法吗?
以下仅为假设:我是否可以使用QtConcurrent在我的QGraphicsItems列表上运行一个方法?如果我在我的QGraphicsItem绘画方法中使用QMutex和我的物理方法中使用QMutex(会更改我的QGraphicsItem的属性),这样是否保证只有一个线程在任何时候读/写每个QGraphicsItem?

我读到了一些关于在连接信号/槽时使用QueuedConnection的内容。虽然我还没有尝试过或深入了解细节,但我认为这值得进一步研究。还有其他人有相关经验吗? - aldo
我使用了Box2D的Delphi端口,并对其非常满意。为什么不尝试一下呢?如果您感兴趣,请访问此页面:http://labs.qt.nokia.com/2010/02/26/qt-box2d-is-easy/。 - menjaraz
Box2D看起来很有趣,但我没有看到它在任何地方是多线程的。 - Joel
QtConcurrent看起来很有趣。我已经有了我的QGraphicsItems列表,如果我可以使用QtConcurrent在每个项目上运行函数,那么物理将会很容易。我的理解是,如果2个线程尝试同时访问同一内存,这可能会导致问题。例如,当QtConcurrent正在修改QGraphicsItem时,它正在被绘制。因此,是否有任何方法可以在QtConcurrent运行时“暂停”场景的绘制? - Joel
1个回答

2
  1. 如果我在我的QGraphicsItem的paint方法中使用QMutex,并在我的物理方法中使用QMutex(这将更改我的QGraphicsItem的属性),这样是否可以保证每次只有一个线程在任何时刻读取/写入每个QGraphicsItem?

    不,它不能。 QGraphicsItem 在绘制时被广泛使用,不仅调用paint方法。例如,看看这里。即使它可以工作,它也是丑陋的解决方案,因为显然,QGraphicsItem 不仅可用于绘画。

  2. 这是否迫使我使用信号/槽机制将最终项目属性(x、y、旋转)每帧发送到主线程,然后使用主线程方法实际更新QGraphicsItems?还是有更简单的方法来做到这一点吗?

    是的,您必须将项目更改过程移动到主线程。您实际上有一些选择:

    • 使用信号/槽机制,如您所提到的。
    • 使用 meta-callsQueuedConnection
    • 发送自定义事件。

    不要忘记,如果您想等待绘图完成,则可以使用 BlockingQueuedConnection

    此外,您可以将所有这些内容与QtConcurent一起使用。

实际上,管理起来并不那么困难。相比手动确保线程安全,它更安全、更容易。更大的问题是,即使尝试在工作线程中仅使用const成员读取项目(例如),您可能仍然会失败。
由于QGraphicsItem不是线程安全的,即使只是读取也是不安全的。我在Qt中进行多线程应用程序开发的经验告诉我,如果有什么不好的事情可能发生,它就会发生。

谢谢您的回答。有一个问题:如果我创建了一个继承自QGraphicsItem的类,并添加了一些自定义属性(颜色、速度等),我是否可以从另一个线程修改这些属性?只要确保每次只有一个线程在读/写每个属性,那么我就没问题了吗? - Joel
@Joel,如果他们没有使用其他继承成员,你可以使用继承。但在这种情况下(_您的_包括QGraphicsItem作为成员),我建议使用聚合而不是继承,因为在这种情况下,这些属性服务于一些单独的目标,而不是实际上扩展QGraphicsItem。我个人认为,这将增加清晰度。 - Lol4t0
我不确定在我的情况下聚合会如何工作。只是为了明确,我想让我的类重新实现绘制方法。我不确定如果不继承QGraphicsItem该怎么做。 - Joel
@Joel,你可以继承自QGraphicsItem并创建一些结构体,这些结构体将与线程一起使用。 - Lol4t0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接