asio::read with timeout

Chris K. picture Chris K. · Oct 29, 2012 · Viewed 22.5k times · Source

I need to know how to read (sync or async doesn't matters) with a timeout. I want to check if a device is connected with a serial port or not.

For that I use asio::write and then I wait for the response of the device.

If a device is connected asio::read(serial, boost::asio::buffer(&r,1)) works fine but if there is no device the program stops, which is is why I need the timeout

I know that I need a deadline_timer but I have no idea how to use it in the async_read function.

An example of how it works would be really helpful.

I know that there are many similar threads and I read lot of them but I can't find a solution that helps me solving my problem!

Answer

Robert Hegner picture Robert Hegner · Jul 29, 2014

The code posted by Igor R. did not compile for me. Here is my improved version of his code, which works perfectly. It uses lambdas to get rid of the set_result helper function.

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