我正在嘗試使用boost :: asio從串口上的設備讀取和寫入。當沒有東西需要讀取時,boost :: asio:read()和boost :: asio :: serial_port :: read_some()模塊。相反,我想檢測這種情況並寫一個命令到端口來啓動設備。如何使用asio執行非阻塞式讀取?
我該如何檢測沒有數據可用?
如果有必要,我可以做所有事情都是異步的,我只想避免額外的複雜性。
我正在嘗試使用boost :: asio從串口上的設備讀取和寫入。當沒有東西需要讀取時,boost :: asio:read()和boost :: asio :: serial_port :: read_some()模塊。相反,我想檢測這種情況並寫一個命令到端口來啓動設備。如何使用asio執行非阻塞式讀取?
我該如何檢測沒有數據可用?
如果有必要,我可以做所有事情都是異步的,我只想避免額外的複雜性。
實際上,您有幾個選項。您可以使用串口的內置async_read_some
功能,也可以使用獨立功能boost::asio::async_read
(或async_read_some
)。
您仍然會遇到有效「阻止」的情況,因爲除非(1)數據已被讀取或(2)發生錯誤,否則它們都不會調用回調。爲了解決這個問題,你需要使用一個deadline_timer
對象來設置超時。如果超時觸發,則沒有數據可用。否則,您將讀取數據。
增加的複雜性並不是那麼糟糕。您將最終得到兩個具有類似行爲的回調。如果「讀取」或「超時」回調觸發錯誤,則知道這是比賽失敗者。如果任何一方發生錯誤,那麼你知道這是比賽獲勝者(你應該取消另一個電話)。在您將阻止撥打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()
的呼叫中處理。不知道你是否已經意識到了這一點......
你必須使用自由函數asio :: async_read。
它實際上是一個很多比答案更簡單的在這裏已經暗示,你可以同步做:
假設你的阻塞讀是這樣的:
size_t len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint);
然後你
socket.non_blocking(true);
size_t len = 0;
error = boost::asio::error::would_block;
while (error == boost::asio::error::would_block)
//do other things here like go and make coffee
len = socket.receive_from(boost::asio::buffer(recv_buf), sender_endpoint, 0, error);
std::cout.write(recv_buf.data(), len);
更換您使用的幾乎所有的發送/接收方法有receive_from的替代重載形式。他們不幸採取了一個標誌參數,但0似乎工作正常。
我已經使用這種方法,它運作良好,但只在第一次。下一次調用io_svc.run()會立即返回。我需要額外做些事嗎?感謝 – Schiavini 2013-02-04 10:44:57
顯然我不得不在io_svc.run()之後調用io_svc.reset()。 – Schiavini 2013-02-04 11:31:23