为啥 QSerialPort::writeData 使用单次计时器开始写入?

Posted

技术标签:

【中文标题】为啥 QSerialPort::writeData 使用单次计时器开始写入?【英文标题】: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 的超时错误检测过程只是一个错误。 【参考方案1】:

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

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

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

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

【讨论】:

以上是关于为啥 QSerialPort::writeData 使用单次计时器开始写入?的主要内容,如果未能解决你的问题,请参考以下文章

为啥使用 glTranslatef?为啥不直接更改渲染坐标?

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?