title: Cancel async_read due to timeout
body: <p>I'm trying to write a wrapper synchronous method around <code>async_read</code> to allow non blocking reads on a socket. Following several examples around internet I have developed a solution that seems to be almost right but which is not working.</p>
  
  <p>The class declares these relevant attributes and methods:</p>
  
  <pre><code>class communications_client
  {
      protected:
          boost::shared_ptr&lt;boost::asio::io_service&gt; _io_service;
          boost::shared_ptr&lt;boost::asio::ip::tcp::socket&gt; _socket;
          boost::array&lt;boost::uint8_t, 128&gt; _data;
  
          boost::mutex _mutex;
          bool _timeout_triggered;
          bool _message_received;
          boost::system::error_code _error;
          size_t _bytes_transferred;
  
          void handle_read(const boost::system::error_code &amp; error, size_t bytes_transferred);
          void handle_timeout(const boost::system::error_code &amp; error);
          size_t async_read_helper(unsigned short bytes_to_transfer, const boost::posix_time::time_duration &amp; timeout, boost::system::error_code &amp; error);
  
          ...
  }
  </code></pre>
  
  <p>The method <code>async_read_helper</code> is the one that encapsulates all the complexity, while the other two <code>handle_read</code>and <code>handle_timeout</code> are just the event handlers. Here is the implementation of the three methods:</p>
  
  <pre><code>void communications_client::handle_timeout(const boost::system::error_code &amp; error)
  {
      if (!error)
      {
          _mutex.lock();
          _timeout_triggered = true;
          _error.assign(boost::system::errc::timed_out, boost::system::system_category());
          _mutex.unlock();
      }
  }
  
  void communications_client::handle_read(const boost::system::error_code &amp; error, size_t bytes_transferred)
  {
      _mutex.lock();
      _message_received = true;
      _error = error;
      _bytes_transferred = bytes_transferred;
      _mutex.unlock();
  }
  
  size_t communications_client::async_read_helper(unsigned short bytes_to_transfer, const boost::posix_time::time_duration &amp; timeout, boost::system::error_code &amp; error)
  {
      _timeout_triggered = false;
      _message_received = false;
  
      boost::asio::deadline_timer timer(*_io_service);
      timer.expires_from_now(timeout);
      timer.async_wait(
          boost::bind(
              &amp;communications_client::handle_timeout,
              this,
              boost::asio::placeholders::error));
  
      boost::asio::async_read(
          *_socket,
          boost::asio::buffer(_data, 128),
          boost::asio::transfer_exactly(bytes_to_transfer),
          boost::bind(
              &amp;communications_client::handle_read,
              this,
              boost::asio::placeholders::error,
              boost::asio::placeholders::bytes_transferred));
  
      while (true)
      {
          _io_service-&gt;poll_one();
          if (_message_received)
          {
              timer.cancel();
              break;
          }
          else if (_timeout_triggered)
          {
              _socket-&gt;cancel();
              break;
          }
      }
  
      return _bytes_transferred;
  }
  </code></pre>
  
  <p>The main question I have is: why this works with a loop on <code>_io_service-&gt;poll_one()</code>and no without a loop and calling <code>_io_service-&gt;run_one()</code>? Also, I would like to know if it looks correct to anyone who is more used to work with Boost and Asio. Thank you!</p>
  
  <hr>
  
  <h2><strong>FIX PROPOSAL #1</strong></h2>
  
  <p>According to the comments done by <a href="https://stackoverflow.com/users/981959/jonathan-wakely">Jonathan Wakely</a> the loop could be replaced using <code>_io_service-&gt;run_one()</code> with a call to <a href="http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/io_service/reset.html" rel="nofollow noreferrer"><code>_io_service-&gt;reset()</code></a> after the operations have finished. It should look like:</p>
  
  <pre><code>_io_service-&gt;run_one();
  if (_message_received)
  {
      timer.cancel();
  }
  else if (_timeout_triggered)
  {
      _socket-&gt;cancel();
  }
  
  _io_service-&gt;reset();
  </code></pre>
  
  <p>After some testing, I have checked that this kind of solution alone is not working. The <code>handle_timeout</code>method is being called continuously with the error code <code>operation_aborted</code>. How can these calls be stopped?</p>
  
  <h2><strong>FIX PROPOSAL #2</strong></h2>
  
  <p>The answer by <a href="https://stackoverflow.com/users/1053968/twsansbury">twsansbury</a> is accurate and based onto solid documentation basis. That implementation leads to the following code within the <code>async_read_helper</code>:</p>
  
  <pre><code>while (_io_service-&gt;run_one())
  {
      if (_message_received)
      {
          timer.cancel();
      }
      else if (_timeout_triggered)
      {
          _socket-&gt;cancel();
      }
  }
  _io_service-&gt;reset();
  </code></pre>
  
  <p>and the following change to the <code>handle_read</code> method:</p>
  
  <pre><code>void communications_client::handle_read(const boost::system::error_code &amp; error, size_t bytes_transferred)
  {
      if (error != boost::asio::error::operation_aborted)
      {
          ...
      }
  }
  </code></pre>
  
  <p>This solution has proved solid and correct during testing.</p>