Boost logo

Boost Users :

Subject: [Boost-users] [asio] sync receive_from with timeout
From: Stephan Menzel (stephan.menzel_at_[hidden])
Date: 2009-03-04 04:23:40


Is the subject Jehova enough for you? ;-)

Great.

Well, I haven't raised the subject so far but I'd certainly like to do so now. For years now I am not only a user but also an admirer of boost asio. Something that has always puzzled me however is, why a timeout functionality which is something very common and essential for sync IO just doesn't seem to be there.

I think there are cases where syncronous IO is a better way to go and no async approach is sensible. In my case this is a collection of static functions that do UDP communication and therefore have to be sync because I just want them to be able to return and throw exceptions and be able to be called from anyone at any time.

As always when I stumble across the asio/timeout problem I start googling around. When people raise the topic here they are usually pointed to an answer Chris Kohlhoff gave to someone asking that:

http://lists.boost.org/Archives/boost/2007/04/120339.php

... which is good for tcp and works alright even though in my opinion it leaves the question why it has to be so compilicated to do something so basic. IMHO sync IO is all but pointless without a timeout.

Anyway, I started to turn this into a UDP version and ended up with something very similar:

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

template <typename MutableBufferSequence>
void udp_read_with_timeout(boost::asio::ip::udp::socket& sock, int tmo, boost::asio::ip::udp::endpoint &endpoint, const MutableBufferSequence& buffers) {

  boost::optional<boost::system::error_code> timer_result;
  boost::asio::deadline_timer timer(sock.io_service());
  timer.expires_from_now(boost::posix_time::seconds(tmo));
  timer.async_wait(boost::bind(set_result, &timer_result, _1));

  boost::optional<boost::system::error_code> read_result;
  sock.async_receive_from(buffers, endpoint, 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 boost::system::system_error(*read_result);
};

So now I started to go ahead with that but I had to notice two things. First, the performance impact is massive to a point that forces me to reconsider. Second, when I use that in a multithreaded environment the whole thing seems to block in some threads randomly. I have made test program where I have multiple threads using that method, just sending an UDP request to a server and waiting for an answer using this function. In one thread everything is slow but continously running. In more than one thread it blocks for up to 5 or 6 seconds every few (10-20) runs for no visible reason. In my scenario all those threads share a socket protected by a mutex so if one of them blocks all will be halted.

So I come to think this is not a good way to handle the problem. Does anyone have some thoughts on that? May this be a bug in asio (1.38) or perhaps in my function? Or is there a better way to do sync UDP IO with a timeout functionality?

Cheers...

Stephan


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net