I'm trying to understand Qt's serial port module and I'm not too familiar with how Qt handles asynchronous I/O. On Windows, the QSerialPort::writeData
method places the data to be written in a ring buffer and then starts a single-shot QTimer
to actually perform the write when its timeout
signal fires:
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;
}
The readData
method doesn't use a timer in this way, instead calling ReadFileEx
directly.
What does the single-shot timer accomplish versus just calling WriteFileEx
?
There is a special case for a QTimer
with an interval of 0: this timer will fire once control returns to the event loop. The implementation on Unix/Linux does something similar, but not using a QTimer, instead having a subclass of QSocketNotifier
that will get called when the port is able to be written to. Both of these implementations mean that you will buffer the data and write it out once you get back to the main event loop.
There are two reasons that I can think of for doing this:
The buffering seems like the most likely reason for this, as doing a syscall for each piece of data that you want to write would be a rather expensive operation.