async_read
操作がシリアルポートで正常に完了し、直ちに別のasync_read
操作を開始してn
バイトを読み取ると、2番目のasync_read
操作成功するとすぐに突然終了し、0バイトが転送されます。boost :: asio :: async_readが完了条件を満たさずに終了する
第
async_read
操作後、第三のasync_read
操作がn
バイトを読み取るために開始された場合、それは成功して完了し、1ミリ秒のスリープが実行される場合n
バイトは// where buffer_size(buffer) and n are both greater than 1 async_read(serial, buffer, transfer_exactly(n), [](error, bytes_transferred) { // completes with error=success and bytes_transferred=n async_read(serial, buffer, transfer_exactly(n), [](error, bytes_transferred) { // complete with error=success and bytes_transferred=0 async_read(serial, buffer, transfer_exactly(n), [](error, bytes_transferred) { // completes with error=success and bytes_transferred=n }); }); });
転送しました第1の動作と第2の動作との間で、第2の動作は成功し、
n
バイトが転送される。// where buffer_size(buffer) and n are both greater than 1 async_read(serial, buffer, transfer_exactly(n), [](error, bytes_transferred) { // completes with error=success and bytes_transferred=n sleep_for(milliseconds(1)); async_read(serial, buffer, transfer_exactly(n), [](error, bytes_transferred) { // completes with error=success and bytes_transferred=n }); });
なぜこのようなことが起こりますか?どのように回避できますか?詳細については
、私はATXMEGA-192A3UでエミュレートRS232経由でマイクロコントローラと通信するには、Windows上でBoost.Asioを使用しています。私はコントローラに開始コマンドを送り、タイムアウトで出力を読みます。コードを以下に示すReadPort
関数を呼び出すことによって出力を読み取りました。プログラムは、次の読み取りタスクを連続して実行します。
- マイクロコントローラの応答を開始コマンドで確認します。この読み込みは、私が期待している3文字を読み取るのに成功しました。
R\r\n
- コントローラからの出力は、数百msの間で
n
バイトです。
ステップ2の操作は、要求されたバイト数を読み取っていないにもかかわらず、正常に完了します。
class BoostBasedCommunication
{
public:
BoostBasedCommunication();
~BoostBasedCommunication(void);
/*...*/
virtual int ReadPort(
int const numberOfCharacters, // maximum number of characters to be read
unsigned long const globalTimeout, // maximum time the operation is allowed to take in ms
unsigned long const intermediateTimeout, // maximum time allowed between two consequtive characters in ms
int& numberOfCharactersRead
);
/*...*/
private:
/*...*/
std::vector<unsigned char> inputBuffer; ///< buffer to save data to that is received
size_t numberOfBytesRead; ///< Number of bytes read
int lastErrorCode; ///< last error code
io_service my_io_service; ///< boost io service class
serial_port port; ///< boost serial port class
/*...*/
};
// Reads from the port until numberOfCharacters have been read, or the
// deadline_timer has expired, or the time between two consecutive calls of
// the completion condition is larger than intermediateTimeoutMS
int BoostBasedCommunication::ReadPort(
int const numberOfCharacters, // maximum number of characters to be read
unsigned long const globalTimeoutMS, // maximum time the operation is allowed to take in ms
unsigned long const intermediateTimeoutMS, // maximum time allowed between two consecutive characters in ms
int& numberOfCharactersRead // Actual number of characters read
)
{
try
{
OutputDebugStringA("ReadPort called\r\n");
my_io_service.reset();
deadline_timer gloabalTimeout(my_io_service);
inputBuffer.resize(numberOfCharacters);
timeoutHandler myGlobalTimeoutHandler(&port);
completion_handler_2 myHandler(&gloabalTimeout, numberOfBytesRead);
completion_condition_2 my_completion_condition(intermediateTimeoutMS, numberOfCharacters);
// Set the timer
gloabalTimeout.expires_from_now(boost::posix_time::milliseconds(globalTimeoutMS));
gloabalTimeout.async_wait(myGlobalTimeoutHandler);
async_read(port, boost::asio::buffer(inputBuffer, numberOfCharacters), my_completion_condition, myHandler);
my_io_service.run(); // run the io service
numberOfCharactersRead = numberOfBytesRead;
}
catch (std::exception&)
{
return COMMUNICATIONFAILED;
}
return NOERROR;
}
class completion_condition_2
{
public:
completion_condition_2(
long intermediateTimeOutTime,
size_t numberOfCharactersTobeRead
) :intermediateTimeOutTime(intermediateTimeOutTime),
numberOfCharactersTobeRead(numberOfCharactersTobeRead)
{}
std::size_t operator()(
const boost::system::error_code& error, // Result of latest async_read_some operation.
std::size_t bytes_transferred // Number of bytes transferred so far.
)
{
if (error)
{
OutputDebugStringA(("completion_condition received error code: " + error.message() + "\r\n").c_str());
if (error.value() == ERROR_OPERATION_ABORTED)
{
return 0;
}
}
/* ...Code concerning the intermediate timeout, which is commented out...*/
if (numberOfCharactersTobeRead <= bytes_transferred) // Enough data has been read
{
std::stringstream message;
message << "completion_condition: bytes transferred: " << bytes_transferred << " of " << numberOfCharactersTobeRead << " => done!" << std::endl;
OutputDebugStringA(message.str().c_str());
return 0;
}
else // More data should be read.
{
std::stringstream message;
message << "completion_condition: bytes transferred: " << bytes_transferred << " of " << numberOfCharactersTobeRead << " => continue!" << std::endl;
OutputDebugStringA(message.str().c_str());
return numberOfCharactersTobeRead - bytes_transferred;
}
}
private:
size_t numberOfCharactersTobeRead; ///< Number of characters to be read
};
class completion_handler_2 {
public:
completion_handler_2(
deadline_timer* _globalTimeout,
size_t& numberOfBytesRead
) :_globalTimeout(_globalTimeout),
numberOfBytesRead(numberOfBytesRead)
{
}
void operator()(
const boost::system::error_code& error, // Result of operation.
std::size_t bytes_transferred // Number of bytes read.
)
{
OutputDebugStringA(("completion handler called with error code: " + error.message() + "\r\n").c_str());
if (error)
{
if (error.value() == ERROR_OPERATION_ABORTED)
{
numberOfBytesRead = bytes_transferred;
return;
}
else
{
BOOST_THROW_EXCEPTION(std::exception("Communication failed"));
}
}
OutputDebugStringA("completion handler: timeout cancelation.\r\n");
_globalTimeout->cancel();
numberOfBytesRead = bytes_transferred;
}
private:
deadline_timer* _globalTimeout; ///< global timeout deadline timer
size_t& numberOfBytesRead; ///< number of bytes read
};
私が期待どおりに動作している最初の読み取りを実行すると、私は次のような出力を受け取ります。
ReadPort called
completion_condition: bytes transferred: 0 of 3 => continue!
completion_condition: bytes transferred: 3 of 3 => done!
completion handler called with error code: success
completion handler timeout cancelation.
timeoutHandler received error code: The I/O operation has been aborted because of either a thread exit or an application request
最初が完了した後、私はすぐに別の読み取りを行う場合は、操作は2ミリ秒後に完了次の出力で:
ReadPort called
completion_condition: bytes transferred: 0 of 1024 => continue!
completion handler called with error code: success // Why is the completion handler called here, although the completion condition did not return 0?
completion handler timeout cancelation.
timeoutHandler received error code: The I/O operation has been aborted because of either a thread exit or an application request
3回目のリード、すぐに最後の1以下の期待通りに動作します:
要するにReadPort called
completion_condition: bytes transferred: 0 of 1024 => continue!
completion_condition: bytes transferred: 8 of 1024 => continue!
...
completion_condition: bytes transferred: 88 of 1024 => continue!
completion_condition: bytes transferred: 96 of 1024 => continue!
timeoutHandler called cancel of seriel port.
completion_condition received error code: The I/O operation has been aborted because of either a thread exit or an application request
completion handler called with error code: The I/O operation has been aborted because of either a thread exit or an application request
これを念頭に置いて、私はコンピュータとマイクロコントローラ間の安定した通信を確立することができました。 しかし、私は1msのタイムアウトの効果を理解していないと思います。マイクロコントローラは、いくつかの点で話し手として機能し、約7.5msごとに8バイトを出力する。私はタイムアウトを打つことなく数百ミリ秒間ポートを読み取ることができます。最初の8バイトの後に通信が中断しないのはなぜですか?次の8バイトが到着するまで1ミリ秒以上かかりますか? –
@PaulR。 'ReadFile'は、1ミリ秒の読み取り間隔タイムアウト設定のために8バイト後にタイムアウトします。あなたの出力では、 'async_read'合成操作で1024バイトを読み込もうとすると、中間の' async_read_some'演算ではそれぞれ8バイトが読み込まれます。 –
私は理解します。したがって、8バイトの後に、私の完了条件コールバックが呼び出されます。これは私が観察しているものです。 –