Ответ 1
На самом деле у вас есть несколько вариантов. Вы можете использовать встроенную функцию async_read_some
для последовательного порта, или вы можете использовать автономную функцию boost::asio::async_read
(или async_read_some
).
Вы все равно столкнетесь с ситуацией, когда вы эффективно заблокированы, поскольку ни один из них не будет вызывать обратный вызов, если только (1) данные не были прочитаны, или (2) произошла ошибка. Чтобы обойти это, вы захотите использовать объект deadline_timer
для установки тайм-аута. Если тайм-аут срабатывает первым, данных не было. В противном случае вы будете читать данные.
Добавленная сложность на самом деле не так уж плоха. Вы получите два обратных вызова с аналогичным поведением. Если срабатывает обратный вызов "read" или "timeout" с ошибкой, вы знаете, что это проигравший в гонке. Если кто-то стреляет без ошибки, то вы знаете это победитель гонки (и вы должны отменить другой звонок). В том месте, где у вас был бы блокирующий вызов 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()
. Не уверен, что вы уже знали об этом...