【问题标题】:Why a new signal for socket::readyRead() is executed, even when its earlier slot is still processing?为什么 socket::readyRead() 的新信号被执行,即使它的早期插槽仍在处理?
【发布时间】:2017-10-05 01:49:43
【问题描述】:

根据以下帖子,仅在当前执行的插槽完成后才会提供发出的信号。
Wait for a SLOT to finish the execution with Qt

我有一个基于 ssl 套接字的客户端-服务器通信应用程序,它是单线程的。

connect(socket, &QSslSocket::readyRead, [&]() { myObject.Read(); });

客户端和服务器互相发送一些自定义消息。无论何时发送或接收消息,它们都会发送 ACK 字节 (00)。
大多数时候,我注意到当Read() 在执行之间时,下一个readyRead() 会被送达!我将调试语句放在myObject->Read() 的开头和结尾。他们确认,开始调试被一次又一次地调用。断点也是如此。

当接收到太多数据时,会创建一个包含太多Read()s 的递归堆栈帧。它要么减慢应用程序 GUI 的速度,要么崩溃。
通常,当客户端尝试将 ACK 作为myObject->Read() 的一部分发送时,就会发生这种递归。在此期间,readyRead() 被偶然发出信号并得到服务。但是前一个信号的槽仍在处理中。

问题

  • 当插槽仍在中间时(单线程),Qt 框架是否可以在两者之间提供信号?
  • 如何修复这种特定于套接字的场景?

注意
- 默认情况下,对于单线程,Qt::ConnectionTypeDirectConnection。我也试过QueuedConnection,但结果是一样的。
- myObject.Read() 相当复杂并且有许多其他的函数调用。如果这引起了问题,那么让我知道我应该寻找什么。编写它的实际代码是不切实际的。

【问题讨论】:

  • 如果myObject->Read() 在您已经在其中时被调用,则很可能在某个时候您已经控制了事件循环。可以加一下函数的代码吗?
  • @BenjaminT,在Read() 方法中有很多与Qt 无关的东西,而是核心功能。编写该代码是不切实际的,因为其中有几种方法。但是,当插槽仍在执行时,事件循环如何控制?你能建议,这在哪些方面是可能的。也许我可以试试看那些。
  • @SamuraiJack,感谢您提供的链接帖子。我试过了,但似乎DirectConnectionQueuedConnection 都会导致相同的行为。有什么东西会导致这个问题吗?请同时查看更新后的 Qn。
  • @iammilind:正如你所说,你在 myObject.Read() 中有很多函数调用,你可以使用 QtConcurrent::run 函数。它允许您异步运行函数。链接 - doc.qt.io/qt-4.8/qtconcurrentrun.html

标签: c++ qt sockets qt-signals qt-slot


【解决方案1】:

readyRead() 的递归调用正在发生,因为事件循环在两者之间被释放。以下函数导致事件循环被释放:

  1. QCoreApplication::processEvents()
  2. SslSocket::flush()

第一个是可以理解的,因为它是为此而生的。但第二个flush() 完全出乎意料。它的documentation 没有这样说明。至少在我的调试中显示,每当调用flush() 时,都会调用并满足后续的readyRead()。在 Qn 中也可以看到。

processEvent() 旨在使 GUI 在高负载数据期间更具响应性。但似乎,我们需要为此做出另一个选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    相关资源
    最近更新 更多