2012-10-29 131 views
10

我需要知道如何閱讀(同步或異步無關緊要)超時。我想檢查一個設備是否與串口連接。asio ::超時讀取

爲此,我使用asio::write,然後等待設備的響應。

如果設備連接asio::read(serial, boost::asio::buffer(&r,1))工作正常,但如果沒有設備的程序停止,這就是爲什麼我需要超時

我知道我需要一個deadline_timer,但我不知道如何使用它在async_read函數中。

一個它如何工作的例子會非常有用。

我知道有很多類似的線程,我閱讀了很多,但是我找不到解決方案來幫助我解決問題!

回答

0

有沒有人或容易答案本身,因爲即使你做一個異步閱讀,回調永遠不會被調用,你現在有一個鬆散的線程周圍的地方。

你是對的,認爲deadline_timer是可能的解決方案之一,但它需要一些擺弄和共享狀態。有blocking TCP example,但那是async_connect,當它沒有任何事情時,它有一個很酷的事情。 read不會這樣做,最壞的情況 - 它會崩潰&刻錄無效資源的原因。所以deadline timer的事情是你的選擇之一,但實際上還有一個更簡單的一個,即去有點像這樣:

boost::thread *newthread = new boost::thread(boost::bind(&::try_read)); 
if (!newthread->timed_join(boost::posix_time::seconds(5))) { 
    newthread->interrupt(); 
} 

基本上,做讀取在另一個線程,並把它扼殺掉,如果超時。你應該閱讀Boost.Threads

如果您中斷它,請確保資源全部關閉。

+3

您確定asio i/o操作是中斷點嗎? –

+0

有沒有人能夠確認這一點?此解決方案是否有效? – rustyx

+0

我已經測試過這個,不適合我。在異步I/O操作期間,中斷不會暫停線程。 – risingDarkness

5

您不要在async_read中使用deadline_timer。但你可以啓動兩個異步進程:

  1. 一個async_read進程串口。 boost::asio::serial_port有一個cancel方法取消所有的異步操作。
  2. 具有所需超時的最後期限計時器。在deadline_timer的完成處理程序中,您可以使用cancel串行端口。這應該關閉async_read操作並調用它的完成處理程序時出錯。

代碼:

#include <iostream> 
#include <boost/asio.hpp> 
#include <boost/bind.hpp> 
#include <boost/date_time/posix_time/posix_time.hpp> 
#include <boost/array.hpp> 

class timed_connection 
{ 
    public: 
     timed_connection(int timeout) : 
      timer_(io_service_, boost::posix_time::seconds(timeout)), 
      serial_port_(io_service_) 
     { 
     } 

     void start() 
     { 
       timer_.async_wait 
       (
       boost::bind 
       (
        &timed_connection::stop, this 
       ) 
       ); 

      // Connect socket 
      // Write to socket 

      // async read from serial port 
      boost::asio::async_read 
       (
       serial_port_, boost::asio::buffer(buffer_), 
       boost::bind 
       (
        &timed_connection::handle_read, this, 
        boost::asio::placeholders::error 
       ) 
       ); 

      io_service_.run(); 
     } 

    private: 
     void stop() 
     { 
      serial_port_.cancel(); 
     } 

     void handle_read (const boost::system::error_code& ec) 
     { 
      if(ec) 
      { 
       // handle error 
      } 
      else 
      { 
       // do something 
      } 
     } 

    private: 
     boost::asio::io_service io_service_; 
     boost::asio::deadline_timer timer_; 
     boost::asio::serial_port serial_port_; 
     boost::array< char, 8192 > buffer_; 
}; 

int main() 
{ 
    timed_connection conn(5); 
    conn.start(); 

    return 0; 
} 
+1

問題**明確**表示他使用串行設備,而不是TCP端點。如果他使用* nix,UNIX套接字可能是一個選項,但操作系統沒有聲明,並且它們具有可移植性。 – TC1

+1

@ TC1,當然,編輯了代碼。從概念上講,Asio將其抽象化,沒有任何變化。 – Vikas

5

曾幾何時,圖書館筆者提出以下方式to read synchronously with timeout(本例中有tcp::socket,但你可以使用,而不是串行端口):

void set_result(optional<error_code>* a, error_code b) 
    { 
    a->reset(b); 
    } 


    template <typename MutableBufferSequence> 
    void read_with_timeout(tcp::socket& sock, 
     const MutableBufferSequence& buffers) 
    { 
    optional<error_code> timer_result; 
    deadline_timer timer(sock.io_service()); 
    timer.expires_from_now(seconds(1)); 
    timer.async_wait(boost::bind(set_result, &timer_result, _1)); 


    optional<error_code> read_result; 
    async_read(sock, buffers, 
     boost::bind(set_result, &read_result, _1)); 

    sock.io_service().reset(); 
    while (sock.io_service().run_one()) 
    { 
     if (read_result) 
     timer.cancel(); 
     else if (timer_result) 
     sock.cancel(); 
    } 


    if (*read_result) 
     throw system_error(*read_result); 
    } 
+0

我不明白這項技術。當沒有其他異步操作可能正在進行時,這可能適用於單線程場景。什麼使得while循環終止?如果還有其他線程,則調用io_service.reset()是一件安全的事情嗎? –

+0

@Tom Quarendon我想你是對的,如果多個線程正在運行io_service,它將不起作用。但是請注意,可以使用io_service-per-core模型,其中每個io_service有一個線程。 –

7

code posted by Igor R.沒有爲我編譯。這是我的改進版代碼,完美的工作。它使用lambdas來擺脫set_result輔助函數。

template <typename SyncReadStream, typename MutableBufferSequence> 
void readWithTimeout(SyncReadStream& s, const MutableBufferSequence& buffers, const boost::asio::deadline_timer::duration_type& expiry_time) 
{ 
    boost::optional<boost::system::error_code> timer_result; 
    boost::asio::deadline_timer timer(s.get_io_service()); 
    timer.expires_from_now(expiry_time); 
    timer.async_wait([&timer_result] (const boost::system::error_code& error) { timer_result.reset(error); }); 

    boost::optional<boost::system::error_code> read_result; 
    boost::asio::async_read(s, buffers, [&read_result] (const boost::system::error_code& error, size_t) { read_result.reset(error); }); 

    s.get_io_service().reset(); 
    while (s.get_io_service().run_one()) 
    { 
     if (read_result) 
      timer.cancel(); 
     else if (timer_result) 
      s.cancel(); 
    } 

    if (*read_result) 
     throw boost::system::system_error(*read_result); 
} 
+0

這很好的模擬'boost :: asio :: async_read'的超時時間。真正簡單和堅實的方法解決問題。我喜歡這種簡單的技術,我想適應'boost :: asio :: async_write'的情況?但它似乎不適用於寫案例。你介意看看[這個問題在這裏](https://stackoverflow.com/questions/47378022/how-to-do-a-boostasioasync-write-with-timeout)? –