- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
在an answer on another question ,据称当使用带有 QSerialPort
的主 Qt 事件循环时,QSerialPort::waitForBytesWritten
会导致“细微错误”,因为它会打开另一个事件循环。
我正在使用 waitForBytesWritten
方法来确保在写入所有字节之前不会重新进入我的主事件循环。这不是执行此操作的有效方法吗?会发生什么“细微错误”?我应该改用 flush()
吗,这是否会确保我的事件循环不会再次进入,直到所有待处理的字节都被写入?
我在我的应用程序中看到了一些与其串行端口通信相关的奇怪行为,但我不确定是哪个通信“层”导致了这个问题,所以它甚至可能不是与我对 QSerialPort
的使用有关。目前,关于它的起源,我得到的唯一提示是 QSerialPort
在我看到不良行为开始之前不久发出了一个 ResourceError
。此 ResourceError
是否与我使用 waitForBytesWritten
有关?
我在 Debian 7 系统上使用 Qt 5.5.1。
最佳答案
在 Unix 上,读取通知将 EAGAIN
、EIO
和 EBADF
映射到 ResourceError
并停止处理进一步阅读通知,直到您调用 waitFor
函数或直到您重新打开端口。这使得 QSerialPort
无法读取,直到您重新打开或 waitFor
。将 EIO
和 EBADF
映射到同一个错误可能是有意义的。但是,由于 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
因为:
它并不像您想象的那样。它所确保的是,通过使用 write
系统调用将数据提供给操作系统,QSerialPort
中的内部写入缓冲区已被清空。这并不意味着数据已经物理发送。
它可能会阻塞。它不能保证阻止。
获取写入完成的通知通常是不必要的。如果您有一个半双工(本质上)命令-响应协议(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/
我对 QTcpSocket::waitForBytesWritten() 的行为有点困惑... 这个函数会阻塞到什么时候? 直到数据写入操作系统的内部缓冲区以通过 TCP 传输? 直到数据被物理转换为
如果我想将数据写入远程端并等待它的响应,我至少需要一个waitForReadyRead。但在调用它之前,我是否需要使用 waitForBytesWritten 手动刷新输出队列,或者 Qt 会自动为我
在an answer on another question ,据称当使用带有 QSerialPort 的主 Qt 事件循环时,QSerialPort::waitForBytesWritten 会导致
QUDPSocket 可以在同步模式下使用而无需事件循环。我找到了下面的例子: #include #include int main() { QTextStream qout(stdout
我是一名优秀的程序员,十分优秀!