実際には、いくつかのオプションがあります。シリアルポートの組み込みasync_read_some
機能を使用することも、スタンドアロン機能boost::asio::async_read
(またはasync_read_some
) を使用することもできます。
(1) データが読み取られるか、(2) エラーが発生しない限り、どちらもコールバックを呼び出さないため、事実上「ブロックされた」状況に陥ります。これを回避するには、deadline_timer
オブジェクトを使用してタイムアウトを設定します。タイムアウトが最初に発生した場合は、データが利用できませんでした。そうしないと、データを読み取ってしまいます。
追加された複雑さは、それほど悪いことではありません。同様の動作を持つ 2 つのコールバックが発生します。「読み取り」コールバックまたは「タイムアウト」コールバックのいずれかがエラーで発生した場合、それはレースの敗者であることがわかります。いずれかがエラーなしで発火した場合、それがレースの勝者であることがわかります (そして、もう一方の呼び出しをキャンセルする必要があります)。へのブロッキング コールがあった場所で、 へread_some
のコールが行われio_svc.run()
ます。関数は を呼び出すときに以前と同じようにブロックされますrun
が、今回は期間を制御します。
次に例を示します。
void foo()
{
io_service io_svc;
serial_port ser_port(io_svc, "your string here");
deadline_timer timeout(io_svc);
unsigned char my_buffer[1];
bool data_available = false;
ser_port.async_read_some(boost::asio::buffer(my_buffer),
boost::bind(&read_callback, boost::ref(data_available), boost::ref(timeout),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
timeout.expires_from_now(boost::posix_time::milliseconds(<<your_timeout_here>>));
timeout.async_wait(boost::bind(&wait_callback, boost::ref(ser_port),
boost::asio::placeholders::error));
io_svc.run(); // will block until async callbacks are finished
if (!data_available)
{
kick_start_the_device();
}
}
void read_callback(bool& data_available, deadline_timer& timeout, const boost::system::error_code& error, std::size_t bytes_transferred)
{
if (error || !bytes_transferred)
{
// No data was read!
data_available = false;
return;
}
timeout.cancel(); // will cause wait_callback to fire with an error
data_available = true;
}
void wait_callback(serial_port& ser_port, const boost::system::error_code& error)
{
if (error)
{
// Data was read and this timeout was canceled
return;
}
ser_port.cancel(); // will cause read_callback to fire with an error
}
これにより、特定のニーズに合わせてあちこちで微調整を行うだけで開始できるはずです。これが役立つことを願っています!
別の注意: コールバックを処理するために余分なスレッドは必要ありませんでした。すべてが への呼び出し内で処理されますrun()
。あなたがすでにこれを知っていたかどうかはわかりません...