У вас есть пара вариантов, на самом деле. Вы можете использовать встроенную функцию последовательного порта 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()
. Не уверен, если вы уже знали об этом ...