Qt的事件循环线程是安全的还是原子的?处理“ QueuedConnection”时如何同步?

时间:2019-04-10 14:41:26

标签: c++ multithreading qt qt-events queued-connection

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

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

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

问题:事件循环本身是线程安全的吗?
即如果Thread1和Thread3都同时向Thread2的事件循环发布了信号,该怎么办?

2 个答案:

答案 0 :(得分:1)

this comment中提到的文章说,事件队列受互斥锁保护。

  

How Qt Signals and Slots Work - Part 3 - Queued and Inter Thread Connections

     

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

     

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

     

将事件添加到队列中之后,并且如果接收者居住在另一个线程中,我们将通过调用QAbstractEventDispatcher::wakeUp将该线程通知给事件调度程序。如果调度程序在等待更多事件时处于睡眠状态,这将唤醒调度程序。如果接收者在同一线程中,则事件将在事件循环迭代时稍后处理。

答案 1 :(得分:1)

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

线程安全

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

原子性

插槽的执行顺序受以下限制:

  • 常用线程抢占
  • 与此插槽进行连接的顺序。
  • 连接到信号的其他插槽。

因此,我不建议为给定的插槽假定特定的执行顺序。

  

如果Thread1和Thread3都同时向Thread2的事件循环发布信号怎么办

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