gpt4 book ai didi

c++ - QSerialPort::waitForBytesWritten "subtle errors"事件循环?

转载 作者:塔克拉玛干 更新时间:2023-11-03 07:13:13 24 4
gpt4 key购买 nike

an answer on another question ,据称当使用带有 QSerialPort 的主 Qt 事件循环时,QSerialPort::waitForBytesWritten 会导致“细微错误”,因为它会打开另一个事件循环。

我正在使用 waitForBytesWritten 方法来确保在写入所有字节之前不会重新进入我的主事件循环。这不是执行此操作的有效方法吗?会发生什么“细微错误”?我应该改用 flush() 吗,这是否会确保我的事件循环不会再次进入,直到所有待处理的字节都被写入?

在我的应用程序中看到了一些与其串行端口通信相关的奇怪行为,但我不确定是哪个通信“层”导致了这个问题,所以它甚至可能不是与我对 QSerialPort 的使用有关。目前,关于它的起源,我得到的唯一提示是 QSerialPort 在我看到不良行为开始之前不久发出了一个 ResourceError。此 ResourceError 是否与我使用 waitForBytesWritten 有关?

我在 Debian 7 系统上使用 Qt 5.5.1。

最佳答案

在 Unix 上,读取通知将 EAGAINEIOEBADF 映射到 ResourceError 并停止处理进一步阅读通知,直到您调用 waitFor 函数或直到您重新打开端口。这使得 QSerialPort 无法读取,直到您重新打开或 waitFor。将 EIOEBADF 映射到同一个错误可能是有意义的。但是,由于 EAGAIN 是良性的,因此以这种方式对待它看起来像是一个 Qt 错误。

要查看是否是问题所在,您可以清除错误并重新调用 waitForReadyRead(0)waitForBytesWritten(0) 并查看错误是否再次出现:

bool retryWaitForBytesWritten(int n, int retries = 10) {
if (!dev.bytesToWrite()) return false;
while (retries-- && !dev.waitForBytesWritten(n)) {
if (dev.error() != QSerialPort::ResourceError)
return false;
dev.clearError(); // retry if it was a resource error
}
return true;
}

你主要不应该使用 waitForBytesWritten 因为:

  1. 它并不像您想象的那样。它所确保的是,通过使用 write 系统调用将数据提供给操作系统,QSerialPort 中的内部写入缓冲区已被清空。这并不意味着数据已经物理发送。

  2. 它可能会阻塞。它不能保证阻止。

  3. 获取写入完成的通知通常是不必要的。如果您有一个半双工(本质上)命令-响应协议(protocol),您不关心何时完成发送,而是关心响应何时到达或超时。

    如果您有一个流式传输协议(protocol),您可以在其中发送轮询命令并且不想生成它们的速度快于设备可以使用它们的速度,那么您应该发出命令(并在数据结构中将它们标记为“已发出”)直到bytesToWrite 已超过高水位线。然后暂停添加新命令,直到 bytesWritten 信号通知您发送缓冲区处于低水位线。 readyRead 插槽匹配对发出的命令的响应并适本地指示它们。

因此,理想情况下,您的代码应包含零个 waitXxx 调用。我们周围的世界是异步的。您不是等待事情发生,而是对它们使用react。在发生某些事情之前不要停止事件循环——这是倒退的。在您等待的那件事之前可能会发生其他事情,直到那时您才忽略它们。即使您将 I/O 推送到一个单独的线程,您仍然在浪费整个线程的阻塞。在顺序伪同步代码中处理重定向控制流的事件也很困难——一切最终都充满了(必要的!)错误检查。有时人们为此求助于使用异常,这可能没问题,但在大型代码库中很难正确执行,并且任何时候您希望将控制重定向到不在调用堆栈上的代码。当您将代码显式表示为分层状态机时,在面对异步事件(例如传入数据或错误)时,推理代码的正确性要容易得多。

设计您的系统,使其基于异步发生的事件进行。如果您的 UI 的某些方面必须指示正在发送的数据的状态,只需这样做:不要等待,不要阻塞线程。

This answer演示了如何使用状态机框架为基于 QIODevice 的设备实现异步 I/O。设置好状态后,将它们与 UI 行为联系起来就相对容易了。查看这些答案:one , two , three , four , five , six , seven , eight .

另外,我错了,我修正了另一个答案。 QSerialPort 不会重新进入事件循环,网络模块中的套接字也不会。

关于c++ - QSerialPort::waitForBytesWritten "subtle errors"事件循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37489220/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com