asio :: read with timeout

时间:2012-10-29 17:35:10

标签: c++ boost timeout serial-port boost-asio

我需要知道如何通过超时读取(同步或异步无关紧要)。我想检查设备是否与串口连接。

为此,我使用asio::write,然后等待设备的响应。

如果设备已连接asio::read(serial, boost::asio::buffer(&r,1))工作正常,但如果没有设备则程序停止,这就是我需要超时的原因

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

它如何运作的一个例子真的很有帮助。

我知道有许多类似的线程,我读了很多,但我找不到能帮助我解决问题的解决方案!

4 个答案:

答案 0 :(得分:11)

code posted by Igor R.没有为我编译。这是我的代码的改进版本,它完美地运行。它使用lambda来摆脱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);
}

答案 1 :(得分:6)

您不在deadline_timer中使用async_read。但是你可以启动两个异步进程:

  1. 串口上的async_read进程。 boost::asio::serial_port有一个cancel方法可以取消对它的所有异步操作。
  2. 具有所需超时的截止时间计时器。在deadline_timer的完成处理程序中,您可以cancel串行端口。这应该关闭async_read操作并调用其完成处理程序时出错。
  3. 代码:

    #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;
    }
    

答案 2 :(得分: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); 
  } 

答案 3 :(得分:0)

本身没有人或简单的答案,因为即使你进行异步读取,回调永远不会被调用,你现在在某处有一个松散的线程。

你认为deadline_timer是可能的解决方案之一是正确的,但它需要一些小小的共享状态。有blocking TCP example,但那是async_connect的,当它无关时返回它是一件很酷的事情。 read不会这样做,最糟糕的情况是 - 它会崩溃&amp;烧掉无效资源的原因。所以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

如果您打断它,请确保资源全部关闭。