【问题标题】:Will disconnecting all signal-slot connections during the execution of a slot prevent all subsequent slots from being called?在插槽执行期间断开所有信号插槽连接会阻止调用所有后续插槽吗?
【发布时间】:2011-05-13 13:19:40
【问题描述】:

假设我有一个 Qt 应用程序,其中有这样的东西:

connect(A, SIGNAL(a()), B, SLOT(b1()));
connect(A, SIGNAL(a()), B, SLOT(b2()));
...
void B::b1() {
  A->disconnect();
}

如果发出a(),那么在从B::b1() 中的A 断开所有插槽后,是否仍会调用插槽B::b2(),因为它们都响应相同的信号?假设两个对象都生活在同一个线程中,所以我们有直接的连接。

我知道disconnect() 会断开与 A 的所有信号连接,但我不确定发出是否只是调度 b1 和 b2 插槽被调用然后调用它们,因此对连接的更改没有效果直到两个插槽(以及发射)返回。所以它可以像这样实现:

emit:
  make temprorary copy of signal's slot table
  foreach element in temporary slot table: call

disconnect:
  clear signal's slot table

否则您可能会遇到数据结构完整性问题。

【问题讨论】:

  • 作为一个模糊的相关说明,Qt 的 foreach 实际上对列表进行了临时复制操作。如果它只是对表执行 Qt foreach,它不会有数据完整性问题。
  • 如果可以,那正是我的解决方案,然后将调用第二个插槽。但我认为元对象系统有点复杂。

标签: qt signals-slots


【解决方案1】:

一个快速的实验表明第二个槽没有被调用。

但是,我不确定这是否是 Qt 所承诺的。

Qt 确实记录了在连接的接收器的迭代过程中进行了某些检查,但这是非常松散且不具体的(而且我在简短的搜索中没有遇到更好的东西);来自http://doc.qt.io/qt-5/signalsandslots.html

这是定位连接对象所需的开销,以安全地迭代所有连接(即检查后续接收器在发射期间是否被破坏)

因此,他们松散地记录了在发出信号时进行了某些检查,例如接收器是否已被破坏。我认为检查连接是否断开似乎是一种类似的情况,但如果能明确记录下来就好了。

因为这听起来对您来说是个问题(您希望所有信号都通过,对吗?),您可以通过确保最后连接到插槽 b1() 的信号来解决此问题. Qt 确实承诺将按连接顺序由信号调用插槽,因此如果您将断开连接的插槽安排为最后一个,则将看到所有其他插槽。

我不知道安排起来有多么容易,但是一个对象会断开另一个对象的槽函数内部的所有内容似乎也有点奇怪(因此可能还有其他一些重构可以解决这个问题) .

如果这些都不可接受,那么为A 的信号提供具有您需要的行为的代理对象就不会太难了。会有一个:

connect(A, SIGNAL(a()), proxy_obj, SLOT(proxy_slot()));

将 A 的信号连接到代理,然后B 可以连接到代理的信号(当代理的插槽被调用时,代理将发出该信号):

connect(proxy_obj, SIGNAL(a()), B, SLOT(b1()));
connect(proxy_obj, SIGNAL(a()), B, SLOT(b2()));

由于 A 的断开连接不会影响代理与 B 的连接,因此代理将确保在发出信号 A->a() 时调用 B 的所有插槽。

class A_proxy : public QObject
{
    Q_OBJECT
public slots:
    void proxy_slot() {
        emit a();
    }

signals:
    void a();
};

【讨论】:

  • 好的,我应该尝试一下。这种行为是否得到保证对我来说并不重要,因为现在我知道我的解决方案不能保证总是有效,谢谢。
  • 其实我已经做了一个变通方法,不是很复杂(有点类似于你的代理解决方案)。但是当它们按连接顺序调用时(我不知道,一定是过度阅读了)这对我也有效,因为修改槽总是最后连接。再次感谢您的详细回答。
【解决方案2】:

disconnect reference page 回答您的问题。

这取决于你如何调用它,以及你调用它的方式(不带任何参数),它会断开对象A上的所有信号,因此断开后不会调用插槽B:b2。

【讨论】:

  • 我了解断开连接的作用,我只是不确定,如果 A::a() 的发射首先安排 b1 和 b2 被调用然后调用它们,所以断开连接直到返回发射没有任何区别。
  • 这不能回答问题。他们断开连接的事实并不意味着对第二个插槽的调用在断开连接之前没有排队。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
  • 2019-02-12
  • 1970-01-01
  • 1970-01-01
  • 2012-10-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多