【问题标题】:Why does QSerialPort::writeData start writes with a single-shot timer?为什么 QSerialPort::writeData 使用单次计时器开始写入?
【发布时间】:2019-10-03 20:33:36
【问题描述】:

我正在尝试了解 Qt 的串行端口模块,但我不太熟悉 Qt 如何处理异步 I/O。在 Windows 上,QSerialPort::writeData 方法将要写入的数据放置在环形缓冲区中,然后在其timeout 信号触发时启动单次QTimer 以实际执行写入:

qint64 QSerialPortPrivate::writeData(const char *data, qint64 maxSize)
{
    Q_Q(QSerialPort);
    writeBuffer.append(data, maxSize);
    if (!writeBuffer.isEmpty() && !writeStarted) {
        if (!startAsyncWriteTimer) {
            startAsyncWriteTimer = new QTimer(q);
            QObjectPrivate::connect(startAsyncWriteTimer, &QTimer::timeout, this, &QSerialPortPrivate::_q_startAsyncWrite);
            startAsyncWriteTimer->setSingleShot(true);
        }
        if (!startAsyncWriteTimer->isActive())
            startAsyncWriteTimer->start();
    }
    return maxSize;
}

readData 方法没有这种方式使用定时器,而是直接调用ReadFileEx

单次计时器与仅调用 WriteFileEx 相比有什么作用?

【问题讨论】:

  • 一个优点是这允许将多个连续的写入调用合并为一个对WriteFileEx 的调用(例如:port.write("a"); port.write("b"); port.write("c"); 都转换为WriteFileEx("abc");)。我不确定是否还有更重要的。
  • 可能是为了实现异步处理。根据设备驱动程序的实现和要发送的数据的大小,有人可能认为直接调用 WriteFileEx 会是一个同步过程。或者可能是打算实现 WriteData 的超时错误检测过程只是一个错误。

标签: windows qt serial-port qtserialport


【解决方案1】:

对于间隔为 0 的 QTimer 有一个特殊情况:一旦控制权返回到 event loop,此计时器将触发。 Unix/Linux 上的实现是 something similar,但不使用 QTimer,而是有一个 QSocketNotifier 的子类,当端口能够被写入时,它将被调用。这两种实现都意味着您将缓冲数据并在返回主事件循环后将其写出。

我能想到这样做有两个原因:

  • POSIX 和 Win32 串行 API 之间存在一些不同之处,需要以这种方式构造代码。据我所知,情况并非如此
  • @Mike 在评论中所说:这将允许数据在写入之前进行缓冲

缓冲似乎是最可能的原因,因为对您要写入的每条数据进行系统调用将是一项相当昂贵的操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-31
    • 1970-01-01
    • 2016-01-29
    相关资源
    最近更新 更多