【问题标题】:Problem with Qt::QueuedConnection, signal delivered after disconnectQt::QueuedConnection 的问题,断开连接后传递的信号
【发布时间】:2011-02-01 16:55:47
【问题描述】:

我刚刚在 Qt 4.6 中发现了队列连接的有趣行为:

建立第一个排队的连接:

connect(someSender, SIGNAL(completed()), this, SLOT(handleCompletion()), Qt::QueuedConnection)

然后 someSender 发送信号:

emit completed()

在接收信号之前(因为它在队列中),我断开信号:

disconnect(someSender, SIGNAL(completed()), this, SLOT(handleCompletion())

不过,handleCompletion 槽会在下一次 eventloop 迭代时被调用。我可以通过在正确的位置使用 someSender->blockSignals(true) 来防止这种情况发生,但更不用说使用一些布尔标志来禁用插槽的功能了。

尤其令我感到惊讶的是,Qt 文档中没有提到这种行为(至少我还没有找到)。

最后一个问题:有什么明智的方法可以避免这种情况发生?

【问题讨论】:

  • 我猜 Qt::QueuedConnection 的实现方式是接收端的队列(事件循环),因此在 disconnect() 之前发出的所有内容都应该进入该队列并留在那里直到它被处理。可能您想调用 disconnect() 与信号发射同步。在其他情况下,是否处理该信号没有太大区别,因为 handleCompletion() 可以更早地完成较早的事件,并且在您预期的场景中完成了()将被处理。 IE。如果您没有指定线程交互的直接场景,您的程序可以按照它想要的方式工作。
  • 如果你愿意,你可以去破解 Qt 代码,它写得很好。

标签: qt


【解决方案1】:

我认为 Qt 的行为方式最为直观。

当您执行emit completed() 时,信号立即激活或排队所有连接的插槽是有意义的。如果排队的插槽可能由于断开连接而取消排队,则将更难以理解,并且更容易出现竞争条件。另外,考虑更复杂的场景:例如所以如果断开连接将其从队列中删除,重新连接是否会将其恢复?

如果它按您预期的方式工作,那么代替这个问题的是“Qt::QueuedConnection 的问题,断开连接后未传递信号”。

至于避免这种情况的明智方法:您应该重新设计代码,以便发送方和接收方都不必关心信号是直接连接还是排队。我建议发送者和接收者都不要调用QObject::connect,这是由第三类完成的。目前尚不清楚这是否会完全解决您的问题,这取决于您在哪里以及为什么要使用disconnect

【讨论】:

  • 好吧,听起来很合理。如果支持“取消排队断开连接”,我仍然会发现可用。是的,没有什么能阻止我自己添加它,除了缺乏空闲时间(并且可能缺乏技能)。
  • 如果您在断开连接的同时破坏了一些资源,并且插槽假定资源始终可访问,那一定是个问题。在这种情况下,你必须在你的插槽中适当地做一些保护。我遇到了这个麻烦,这就是我在这里的原因。
猜你喜欢
  • 2013-02-09
  • 1970-01-01
  • 2021-02-15
  • 1970-01-01
  • 2013-07-14
  • 1970-01-01
  • 1970-01-01
  • 2012-06-20
  • 2023-03-03
相关资源
最近更新 更多