Qt的事件循环线程是安全的还是原子的?处理"队列连接"时如何同步?

Is Qt's event loop thread safe or atomic? How is it synchronised when dealing with `QueuedConnection`?

本文关键字:连接 何同步 同步 队列 循环 安全 事件 线程 原子的 处理 Qt      更新时间:2023-10-16

假设 2 个QThread正在运行,具有以下关系:

connect(&Object1OfThread1, &Object1::Signal, 
&Object2OfThread2, &Object2::Slot, Qt::QueuedConnection);

因此,当来自一个线程的对象引发信号时,将调用另一个线程的插槽。正如Qt信号(QueuedConnection和DirectConnection)中所讨论的,由于Qt::QueuedConnectionSignal()被发布/附加到Thread2的事件循环中。当它轮到时,Slot()被调用。

:事件循环本身是否线程安全?
即,如果线程 1 和线程 3 同时将信号发布到 Thread2 的事件循环中,该怎么办?

此评论中提到的文章说事件队列受互斥锁保护。

Qt信号和插槽的工作原理 - 第3部分 - 排队和线程间连接

QueuedConnection会将事件发布到事件循环以最终处理。

发布事件(QCoreApplication::postEvent年)时,事件将在每线程队列(QThreadData::postEventList)中推送。事件队列受互斥锁保护,因此当线程将事件推送到另一个线程的事件队列时,没有争用条件

将事件添加到队列后,如果接收方位于另一个线程中,我们通过调用QAbstractEventDispatcher::wakeUp来通知该线程的事件调度程序。如果调度程序在等待更多事件时处于睡眠状态,这将唤醒调度程序。如果接收器位于同一线程中,则事件将在稍后处理,因为事件循环会迭代。

Qt事件循环是线程安全的,但不是原子的。

螺纹安全

只要Object2OfThread2状态总是被与Thread2关联的线程修改,就不会有任何竞争条件。最多一个插槽将在任何时候执行。

原子数

插槽的执行顺序由以下因素决定:

  • 通常的线程抢占
  • 与此插槽建立连接的顺序。
  • 连接到信号的其他插槽。

所以我不建议假设给定插槽的特定执行顺序。

如果线程 1 和线程 3 同时将信号发布到 Thread2 的事件循环中,该怎么办

  • 首先,它是不同的信号:两个线程不能发出同一对象的相同信号,因为该对象仅驻留在一个QObject中
  • 首先连接的信号获胜,假设这些信号仅连接到Object2OfThread2,即使它们同时"发布"。
  • 例如,如果 Thread1 信号连接到其他信号\插槽,并且这些连接是在Object2OfThread2, &Object2::Slot之前建立的,它们将在发布到事件循环Object2OfThread2之前进行处理。如果信号同时发出,Thread3 信号将第一个排队,因此第一个执行。