boost::asio::async_read ends without fulfilling the completion condition

∥☆過路亽.° 提交于 2019-11-28 14:30:32

In short, the fundamental problem is either:

  • Asio's interpretation of the ReadFile API contract with timeouts is incorrect
  • a communication driver is violating the ReadFile API contract

The easiest solution is to account for this behavior in the application code, and issue another async_read operation if the prior one completes with success and 0 bytes read. Depending on the communication driver's implementation, a 1 milliseconds sleep between reads may work.


The COMMTIMEOUTS documentation states that for the read interval timeout:

The maximum time allowed to elapse before the arrival of the next byte on the communications line, in milliseconds. If the interval between the arrival of any two bytes exceeds this amount, the ReadFile operation is completed and any buffered data is returned. [...]

Asio's interpretation of the documentation, namely the emphasized text, is that for a given ReadFile operation, the read interval timeout begins after the first byte has been read. The implication is that if ReadFile is requested to read more than 0 bytes, Asio does not expect the ReadFile operation to return a status indicating it has successfully read 0 bytes synchronously or asynchronously. With this interpretation, Asio's implementation configures the serial port with a read interval timeout of 1 millisecond1.

// Set up timeouts so that the serial port will behave similarly to a
// network socket. Reads wait for at least one byte, then return with
// whatever they have. Writes return once everything is out the door.
::COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 1;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;

The async_read is a composed operation implemented in zero or more calls to intermediate async_read_some operations. The async_read operation interprets an intermediate async_read_some operation completing with success and 0 bytes transferred as-if no further progress will be made for the composed operation, and thus the async_read operation completes. This interpretation becomes problematic when the underlying system call to ReadFile unexpectedly completes synchronously with success and 0 bytes read.

With this details, alternative solutions are to either:

  • patch the communication driver so that a timeout interval only begins for a ReadFile operation once the operation has read at least a single byte
  • patch Asio. If one has detailed the observed behavior of ReadFile and finds that it only occurs if the ReadFile operation completes synchronously, then one may be able to patch the async_read_some() operation within win_iocp_handle_service::start_read_op. Otherwise, one could patch the various read_op specializations so that their completion predicate does not exit if 0 bytes have been read, but more than 0 had been requested.

1. If the communication driver's implementation is allowing the read interval timeout that started at the last byte read for ReadFilen operation to affect ReadFilen+1 operation that is initiated within the read interval timeout gap, then sleeping between ReadFilen and ReadFilen+1 for the period of the read interval timeout would prevent the Asio read operations from completing with success and 0 bytes when the supplied buffer's size is greater than 0 bytes.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!