[asio] sync receive_from with timeout

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::optionalboost::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::optionalboost::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::optionalboost::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

Stephan,
I had to program smth similar. Than a tried some "non-standard" approach. If
you use boost threads to handle socket communication, when the socket is
blocked you can interrupt the thread which owns the socket. You will receive
the interruption exception and handle your socket cancel there. This is not
documentation conform in so far, since boost::thread doc states, that you
might only cancel threads which are in an interruption point or will enter
it. Asio or Boost::Threads simply ignore each other and nowhere in the docs
of asio is stated smth about boost::threads, but as it seems asio socket
when it waits for input is in such an interruption point (may be it uses
boost::threads internally) and therefore can be interrupted, but that's not
documented. I tested this with gcc compiler and it worked. May be this would
be a possible fix for asio developers to promise that synchronous sockets
are interruptable via boost::thread interruption.
Actually in my case it was a prototype, and it stayed so and I probably
would never rely on that in the production code, but wanted to show that
there might be a quick fix for this issue.
Best Regards,
Ovanes
On Wed, Mar 4, 2009 at 10:23 AM, Stephan Menzel
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::optionalboost::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::optionalboost::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::optionalboost::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 mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

Hi Ovanes,
not documented. I tested this with gcc compiler and it worked. May be this would be a possible fix for asio developers to promise that synchronous sockets are interruptable via boost::thread interruption.
Actually in my case it was a prototype, and it stayed so and I probably would never rely on that in the production code, but wanted to show that there might be a quick fix for this issue.
Well, an interesting approach. Alas, I'd rather not stray so far into the realm of workarounds but try to solve the issue in a more standard and mean-to-be way. Also it has to work on windows and several unix flavours. My favorite solution would be the boost community would consider to include timouts in sync IO hence making it useful and adding value to asio. I'm not sure whether I understand correctly what you suggest but wouldn't that affect the socket itself rather than the code using it? In my case the socket is a static object and protected via mutex so there's no thread ownership in general sense. Cazart, Stephan

Well, an interesting approach. Alas, I'd rather not stray so far into the
realm of workarounds but try to solve the issue in a more standard and mean-to-be way. Also it has to work on windows and several unix flavours. My favorite solution would be the boost community would consider to include timouts in sync IO hence making it useful and adding value to asio.
I'm not sure whether I understand correctly what you suggest but wouldn't that affect the socket itself rather than the code using it? In my case the socket is a static object and protected via mutex so there's no thread ownership in general sense.
Well, my suggestion was the following: If the socket is blocked in a thread, the thread is blocked as well (and luckily boost::thread recognizes it as an iterruption point). Issue interrupt to that thread and the socket's wait will be interrupted. I don't remember If the socket is consistent after this operation, but I know it worked and I was able to close it as if nothing happened. Hope that clarifies the issue, Ovanes

Hi Ovanes,
Well, my suggestion was the following: If the socket is blocked in a thread, the thread is blocked as well (and luckily boost::thread recognizes it as an iterruption point). Issue interrupt to that thread and the socket's wait will be interrupted. I don't remember If the socket is consistent after this operation, but I know it worked and I was able to close it as if nothing happened.
Hope that clarifies the issue,
Ah, right. Yes it does. That seems rather tricky to implement. I just had a little try on it and I noticed that in order to interrupt the thread calling the blocking wait one would need this thread's boost::thread object. Which cannot be obtained from the this_thread::id. So each thread calling that interruptable receive would have to have it's boost::thread object to pass it to the function, right? I can't see how I could expose all this to the interface of this method. I think it has to be closer to asio. Cheers, Stephan

On Wed, Mar 4, 2009 at 12:09 PM, Stephan Menzel
Hi Ovanes,
Well, my suggestion was the following: If the socket is blocked in a thread, the thread is blocked as well (and luckily boost::thread recognizes it as an iterruption point). Issue interrupt to that thread and the socket's wait will be interrupted. I don't remember If the socket is consistent after this operation, but I know it worked and I was able to close it as if nothing happened.
Hope that clarifies the issue,
Ah, right. Yes it does. That seems rather tricky to implement. I just had a little try on it and I noticed that in order to interrupt the thread calling the blocking wait one would need this thread's boost::thread object. Which cannot be obtained from the this_thread::id. So each thread calling that interruptable receive would have to have it's boost::thread object to pass it to the function, right? I can't see how I could expose all this to the interface of this method. I think it has to be closer to asio.
Cheers,
Stephan
Yes, you probably need to pass a thread reference to be interrupted after some timeout, otherwise that would not work. Ovanes.

Hi Ovanes,
So each thread calling that interruptable receive would have to have it's boost::thread object to pass it to the function, right? ... Yes, you probably need to pass a thread reference to be interrupted after some timeout, otherwise that would not work.
Well, I just tried to work around that with io_services running thread pools and all but there's little hope as all things I could come up with that realize this would require the thread object. The only thing I could imagine would be an extra thread which could be created to execute the blocking IO starts, while the original thread goes into a sleep that can be interrupted by the new thread upon successfuly return of the blocking read. like this (pseudo): void readthread() { // go into blocking read sock.sync_receive_from(...); } original thread: ... thread t1(readthread); try { boost::this_thread::sleep(timeout) } catch (const boost::thread_interrupted &e) { } ..but that would of course mean a new thread each time and I don't think it'll work. Looks like I'm gonna have to find another way. Cheers... Stephan

Stephan,
what about that:
On Wed, Mar 4, 2009 at 3:20 PM, Stephan Menzel
like this (pseudo):
void readthread() { try
{
// go into blocking read sock.sync_receive_from(...);
// signal successful read } catch(boost::thread_interrupted const& e) { //handle interruption }
}
original thread:
... thread t1(readthread); boost::this_thread::sleep(timeout);
if(/*not signaled successful read*/) t1.interrupt(); Regards, Ovanes

Just a small addition. Instead of sleep, you can use a condition variable
and wait on it with timeout. So the if condition would be smth like:
if(!timed_wait(cond, timeout))
t1.interrupt();
On Wed, Mar 4, 2009 at 3:30 PM, Ovanes Markarian
Stephan,
what about that:
On Wed, Mar 4, 2009 at 3:20 PM, Stephan Menzel
wrote: like this (pseudo):
void readthread() { try
{
// go into blocking read sock.sync_receive_from(...);
// signal successful read } catch(boost::thread_interrupted const& e) { //handle interruption }
}
original thread:
... thread t1(readthread); boost::this_thread::sleep(timeout);
if(/*not signaled successful read*/) t1.interrupt();
Regards, Ovanes

Ovanes,
Just a small addition. Instead of sleep, you can use a condition variable and wait on it with timeout. So the if condition would be smth like:
if(!timed_wait(cond, timeout)) t1.interrupt();
Well, I just started to implement this and I still get some erratic behaviour. Also I think in order to be consistent this can't be modular enough. There's the condition variable as well as the mutex around it (one more to the one I already use to protect the socket) and the thread function that needs to be bound to this object. All feasable and yet way to much complexity within the app compared to socket.receive_from(buffer, timeout), which I just noticed as I am currently using the originally posted receive_with_timeout in 2 classes already. I don't think I want all that and the thread still needs to be created and paid for. I think I'll look into io_service.post. When the object that socket belongs to is created I can start several threads and use them as a pool. Then I might just use a timer, kill the socket and reinstanciate it. I hope this will make the blocking read return. It shouldn't happen too often anyway. In addition I'll also prepare to post this as a bug report to asio. Frankly I tend to consider the absence of such functionality a bug. If you offer sync IO you gotta include it. Don't get me wrong, asio is a phantastic lib but this needs to be done. IMHO either by including it or by removing sync IO entirely. Workarounds are not a solution. Cheers... Stephan

Stephan,
I agree with you about timeout parameter. I might try tonight to code this
behavior as work to be sure, that I did not suggest smth. completely out of
scope.
Best Regards from Munich (to Munich I assume)
Ovanes
On Wed, Mar 4, 2009 at 5:51 PM, Stephan Menzel
Ovanes,
Just a small addition. Instead of sleep, you can use a condition variable and wait on it with timeout. So the if condition would be smth like:
if(!timed_wait(cond, timeout)) t1.interrupt();
Well, I just started to implement this and I still get some erratic behaviour. Also I think in order to be consistent this can't be modular enough. There's the condition variable as well as the mutex around it (one more to the one I already use to protect the socket) and the thread function that needs to be bound to this object. All feasable and yet way to much complexity within the app compared to socket.receive_from(buffer, timeout), which I just noticed as I am currently using the originally posted receive_with_timeout in 2 classes already. I don't think I want all that and the thread still needs to be created and paid for.
I think I'll look into io_service.post. When the object that socket belongs to is created I can start several threads and use them as a pool. Then I might just use a timer, kill the socket and reinstanciate it. I hope this will make the blocking read return. It shouldn't happen too often anyway. In addition I'll also prepare to post this as a bug report to asio. Frankly I tend to consider the absence of such functionality a bug. If you offer sync IO you gotta include it. Don't get me wrong, asio is a phantastic lib but this needs to be done. IMHO either by including it or by removing sync IO entirely. Workarounds are not a solution.
Cheers...
Stephan

Asio or Boost::Threads simply ignore each other and nowhere in the docs of asio is stated smth about boost::threads, but as it seems asio socket when it waits for input is in such an interruption point (may be it uses boost::threads internally)
Are you sure asio launches threads, besides the ones you supplied for io_service::run()?

On Wed, Mar 4, 2009 at 11:23 AM, Igor R
Asio or Boost::Threads simply ignore each other and nowhere in the docs of asio is stated smth about boost::threads, but as it seems asio socket when it waits for input is in such an interruption point (may be it uses boost::threads internally)
Are you sure asio launches threads, besides the ones you supplied for io_service::run()?
No, that was not my point. If you use a socket from multiple threads and read data from it, socket blocks waiting for input. My point was, that this blocking wait is recognized by boost::thread lib as a valid interruption point. And my suggestion would be to state in the docs of Asio that synchronous wait operation is a valid interruption point for boost::thread. Sorry for misleading words. Therefore interrupting the thread should interrupt the synchronous wait.
participants (3)
-
Igor R
-
Ovanes Markarian
-
Stephan Menzel