0

虽然Qt::QueuedConnectionor Qt::AutoConnection(在某些情况下)在多线程环境中是首选,但我问这个问题是为了我的理解目的。

  1. 如果MySignal()在线程 A 中发出信号并且插槽MySlot()属于线程 B 的对象。两者都通过 连接Qt::DirectConnection,执行如何发生?即如果线程 A 向线程 B 发送信号,而线程 B 正在执行某个函数的中间foo()MySlot()将在完成后立即调用插槽foo()还是将其并行调用foo()

  2. 在多线程应用程序中是否存在Qt::DirectConnection比其他应用程序更理想的情况?

4

2 回答 2

2

如果线程 A 向线程 B 发送信号,而线程 B 正在某个函数 foo() 的中间执行。是在 foo() 完成后调用插槽 MySlot() 还是与 foo() 并行调用?

不幸的是(正如您所怀疑的那样)Qt::DirectConnection正是这样,并且B::MySlot()将在线程 A 上与线程 B 上已经发生的任何事情同时被调用——foo()在这种情况下。因此,如果没有任何其他形式的同步,Qt::DirectConnection当发送方和接收方可能在不同的线程上时,使用通常是一个坏主意。

如果您确实需要同步跨线程信号/槽调用的概念,那么您可能需要查看Qt::BlockingQueuedConnection

于 2019-12-28T17:45:01.063 回答
2

在多线程应用程序中是否存在DirectConnection比其他应用程序更理想的情况?

是的,如果您的线程B仅在单个函数中执行并且没有事件循环,那么这是您唯一选择。使用or将不起作用,因为相应的插槽调用事件将不会在其他任何地方或任何地方处理。DirectConnectionAutoConnectionQueuedConnectionB

另一个原因DirectConnection可能是您的参数不能使用 Qt 元对象系统进行序列化/反序列化。如果Qt::DirectConnection满足条件(插槽是线程安全的),您可以改用它(注意后果 - 请参阅以下文本)。

您必须考虑的另一件事是跨多个插槽的信号分布。如果您使用DirectConnection并且该插槽需要在互斥体上等待,则在该插槽之后连接的其他插槽将不会被激活,直到该插槽返回。在这种情况下使用QueuedConnection将提供非阻塞信号分布。然后,线程 B 将阻塞(在其插槽调用事件的 qt 内部事件处理程序中),而不是在其“emit”语句中的线程 A。

您必须考虑的另一件事是插槽调用顺序。如果你emit一个接一个地发出多个语句,并且同一个对象的槽被调用 using QueuedConnection,它们是按这个顺序调用的,因为后面是普通的槽调用事件。如果其中一些槽是DirectConnection,那么它们在发射线程中被同步调用,相对于其他排队的槽调用没有顺序保证!

编辑:我认为QObject::deleteLater也有一个有趣的案例。我建议使用Qt::DirectConnection. 此函数是线程安全的,并将向对象的目标线程发送一个 delete-later 事件。更重要的是,该函数还处理对象的线程没有运行事件循环的情况(在这种情况下,对象在其线程退出时被删除)。如果您要使用Qt::QueuedConnection并且目标线程中没有事件循环,那么您将创建内存泄漏。

于 2019-12-28T17:58:21.133 回答