Bạn có một số tùy chọn. Bạn có thể sử dụng chức năng async_read_some
tích hợp của cổng nối tiếp hoặc bạn có thể sử dụng chức năng độc lập boost::asio::async_read
(hoặc async_read_some
).
Bạn sẽ vẫn gặp phải tình huống bạn bị "chặn" một cách hiệu quả, vì cả hai sẽ không gọi lại trừ khi (1) dữ liệu đã được đọc hoặc (2) xảy ra lỗi. Để giải quyết vấn đề này, bạn sẽ muốn sử dụng đối tượng deadline_timer
để đặt thời gian chờ. Nếu hết thời gian chờ, không có sẵn dữ liệu. Nếu không, bạn sẽ có dữ liệu đọc.
Độ phức tạp thêm không thực sự tồi tệ. Bạn sẽ kết thúc với hai cuộc gọi lại với hành vi tương tự. Nếu cuộc gọi lại "đọc" hoặc "thời gian chờ" kích hoạt với lỗi, bạn biết đó là cuộc đua thua cuộc. Nếu một trong hai đám cháy mà không có một lỗi, sau đó bạn biết đó là người chiến thắng cuộc đua (và bạn nên hủy bỏ cuộc gọi khác). Ở nơi bạn sẽ có cuộc gọi chặn đến read_some
, bây giờ bạn sẽ có cuộc gọi đến io_svc.run()
. Chức năng của bạn sẽ vẫn chặn như trước khi nó gọi run
, nhưng lần này bạn kiểm soát thời lượng.
Dưới đây là một ví dụ:
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
}
Điều đó sẽ giúp bạn bắt đầu với chỉ một vài điều chỉnh ở đây và ở đó cho phù hợp với nhu cầu cụ thể của bạn. Tôi hi vọng cái này giúp được!
Lưu ý khác: Không cần thêm chuỗi chủ đề nào để xử lý cuộc gọi lại. Mọi thứ được xử lý trong cuộc gọi đến run()
. Bạn không chắc chắn nếu bạn là đã nhận thức được điều này ...
Tôi đã sử dụng phương pháp này và phương pháp này hoạt động tốt nhưng chỉ ở lần đầu tiên. Cuộc gọi tiếp theo tới io_svc.run() trả về ngay lập tức. Tôi có cần phải làm gì thêm không? Cảm ơn – Schiavini
dường như tôi đã gọi io_svc.reset() sau io_svc.run(). – Schiavini
câu trả lời tuyệt vời, rất hữu ích. Tuy nhiên, tôi nhận được một số hành vi lạ: Tôi có một chương trình ghi dữ liệu vào cổng nối tiếp sau mỗi 5 ms và một số khác đọc, tuy nhiên nếu tôi đặt độ trễ async thành 5 ms trên phần đầu đọc, tôi vẫn nhận được một số dữ liệu không có sẵn các cuộc gọi được trộn lẫn với các giá trị đọc.Đây có phải là do một số chi phí trên mã hoặc tôi thiếu một cái gì đó? – joaocandre