[Development] [QIODevice]How to correctly treat/understand of the documentation?

Denis Shienkov denis.shienkov at gmail.com
Fri Apr 18 16:14:43 CEST 2014


Hi.

I once again fluently look source codes of Qt and I see that the only one
I/O class which supports a buffered mode is QTcpSocket (i.e.
QAbstractSocket in buffered mode); in which is used the "deferred" writing
for data transfer.

Thus, whether can I take such behavior (with "deferred" writing) as a basis
for implementation of I/O in QtSerialPort where only buffered mode is used
(as in QTcpSocket) ?

Because I don't see other precedents and examples which to take as a basis.

What do you think?

PS: As it is very important part of the project.

BR,
Denis




2014-04-18 14:32 GMT+04:00 Denis Shienkov <denis.shienkov at gmail.com>:

> Hi.
>
> My question most likely belongs to the Qt developers from Digia. For
> example to maintainers of a "network" subsystem.
>
> I see that in QAbstractSocket::write() in a buffered mode is used the
> "deferred" data transmission:
>
>
> https://qt.gitorious.org/qt/qtbase/source/454dc332b3856c1726683595575c34281650a469:src/network/socket/qabstractsocket.cpp#L2443
>
> i.e. data are transferred not immediately, but only after the
> writeNotifier triggering (i.e. after "Tx-empty" event has been triggered).
>
> For me it is interest, why we have this behaviour? What reason in it?
>
> e.g., currently we have (for buffered mode):
>
> [code]
>
> qint64 QAbstractSocket::writeData(const char *data, qint64 size)
>
> {
>
>     ...
>
>     char *ptr = d->writeBuffer.reserve(size);
>
>     ...
>
>     memcpy(ptr, data, size);
>
>
>     qint64 written = size;
>
>
>     if (d->socketEngine && !d->writeBuffer.isEmpty())
>
>         d->socketEngine->setWriteNotificationEnabled(true);
>
>
>         //        // why we do not write whole data from buffer here?        // why we skip this, until the notifier was triggering on some next Qt-event loop?
>
>         return written;
>
> }
>
>
> [/code]
>
> Why it isn't made for example so ??:
>
> {code}
>
> qint64 QAbstractSocket::writeData(const char *data, qint64 size)
>
> {
>
>     ...
>
>     char *ptr = d->writeBuffer.reserve(size);
>
>     ...
>
>     memcpy(ptr, data, size);
>
>
>     qint64 written = size;
>
>
>     if (d->socketEngine && !d->writeBuffer.isEmpty()) {
>
>                 //
>
>         // trying to write whole data from buffer immediately if still we do not have an running streaming
>
>         //
>
>                 d->flush(); // or d->write or something, i.e. we just write data to device
>
>                         d->socketEngine->setWriteNotificationEnabled(true);
>
>     }
>
>
>     ...
>
>         return written;
>
> }
>
>
>
> {code}
>
> BR,
> Denis
>
>
> 2014-04-18 0:18 GMT+04:00 Carlos Duclos <carlosduclosv at yahoo.com>:
>
> Hi,
>>
>> I'm not sure I understand your question so I'll reply according to what I
>> understood.
>>
>> QIODevice is a generic interface and as such has to provide an interface
>> that works well with different ways of doing things. What seems to confuse
>> you is the possibility of doing buffered communications and non-buffered
>> communications.
>>
>> There is no simple answer to what is correct when it comes to buffered
>> versus non-buffered. There are too many variables involved in making such a
>> decision and therefore QIODevice is flexible enough to work with both
>> approaches. For some type of devices a buffered approach is preferred for
>> some applications while a non-buffered approach might work best in other
>> situations.
>>
>> For example, if your application requires sending chunks of data once a
>> day (let's think of a control device hanging somewhere in a building) and
>> the data is computed before sending it, then a buffered approach might be
>> the right solution. You do your calculation, print what you need to print
>> and once you are done with that the device might empty the buffer and
>> continue. This is a common situation in embedded devices that are connected
>> over slow communication lines, such as RS232 or RS485 (or even 422). If the
>> device is instead connected to a fast communication line and it requires to
>> send data often, then writing it directly might be the right choice.
>>
>> There is no unique way to answer the problem without knowing exactly what
>> you are trying to do. What QIODevice allows you is to implement your own
>> device that works as you need it. If buffering is the right solution to
>> your problem then you use buffering, if not you don't use it. If it is
>> difficult to decide which approach, implement both and let the open method
>> tell you which one to use. The key point is that you can specialize your
>> device as much as you want and the interface will allow it.
>>
>> In the case of a serial port, then there are already several layers of
>> buffering starting at the hardware level all the way to the OS. This allows
>> to write a lot of data but at the cost of introducing delays that might be
>> difficult to control.
>>
>> Regarding your final question about how many bytes you will receive, it
>> is difficult to answer without knowing more details such as what kind of
>> device you were using.
>>
>> If I missed the point and I did not understand your questions, please
>> accept my apologies and ask the question in another way.
>>
>> Cheers!
>>
>> >Hi all.
>> >
>> >I have the question concerning correct treatment of documentation and
>> >implementation of I/O methods, e.g. for QtSerialPort.
>> >
>> >== write ==
>> >
>> >For example, regarding to the QIODevice::write() method. Investigating of
>> >Qt5 source codes I see two approaches in classes derived from >QIODevice
>> (I
>> >talk about the buffered mode):
>> >
>> >1) "Deferred writing"
>> >
>> >When QIODevice::write () only adds a next portion of data to the internal
>> >write buffer. But real data transmission is carried out later, on an next
>> >step: on a signal from an notifier (for example from the Tx FIFO event,
>> >that signalise about FIFO is empty and can be sent next portion of data
>> >from the internal buffer).
>> >
>> >This behavior is implemented, for example in the QAbstractSocket for a
>> >buffered mode.
>> >
>> >2) "Directly writing"
>> >
>> >This approach when the QIODevice::write() transfers data at once to the
>> >device, directly.
>> >
>> >I.e. in my head there is a confusion. How it is necessary to do for the
>> >buffered mode more correctly?
>> >For me, more pleasant that is the first method...
>> >
>> >But, if I am not right (i.e. when need to use "directly" writing to
>> >minimize time between packets), then what reasons in TCP socket the
>> >first
>> >"deferred" method is used?
>> >
>> >== flush ==
>> >
>> >What expected behavior for the QIODevice::flush() method and for the
>> >bytesWritten(qint64) signal?
>> >
>> >For example two scenarios:
>> >
>> >1) Without flush()
>> >
>> >MyClass::foo()
>> >{
>> >    p.write('a');
>> >    p.write('b');
>> >}
>>
>> >MyClass::bar()
>> >{
>> >    p.write('c');
>> >    p.write('d');
>> >}
>> >
>> >when, the bar() method were called after foo() (with some delay), but
>> >when
>> >not all data ("a" and "b") was written (e.g. was in time written only
>> "a").
>> >
>> >then I expected to receive two: bytesWrittenSignal(2 byte) +
>> >bytesWrittenSignal(2 byte)
>> >
>> >
>> >2) With flush()
>> >
>> >MyClass::foo()
>> >{
>> >    p.write('a');
>> >    p.write('b');
>> >}
>> >
>> >MyClass::bar()
>> >{
>> >    p.write('c');
>> >    p.write('d');
>> >    p.flush();
>> >}
>> >
>> >when, the bar() method were called after foo() (with some delay), but
>> >when
>> >not all data ("a" and "b") was written (e.g. was in time written only
>> "a").
>> >
>> >then I expected to receive one bytesWrittenSignal(4 byte)
>> >
>> >Whether correctly I understand?nd for expected behavior?
>> >
>> >
>> >Best regards,
>> >Denis
>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20140418/e31868c1/attachment.html>


More information about the Development mailing list