views:

89

answers:

4

Hello. I am using the excellent asio for an asynchronous network client. When handling read (async_read) I am concerned that the method/function handling the data might hang or take too long (the function is supplied by the user of the class).

What is the best way of calling the supplied function and ensuring it won't take too long ?

Thank you for your time.

+1  A: 

You could write a wrapper function which launches the given handler in a separate thread and does a timed_join on it. If the timeout reaches, you could throw an exception or do whatever else you want.

Armen Tsirunyan
This is very interesting. How do I launch a function/method in another thread ?
nc3b
@nc3b: you create an instance of boost::thread class (http://www.boost.org/doc/libs/1_44_0/doc/html/thread.html) and pass the function/method as the argument. The abovementioned timed_join is the member of boost::thread class.
Armen Tsirunyan
@Armen Tsirunyan: I could do this, but spawning another thread for each packet received might be a bit of a performance hit
nc3b
@nc3b: Good point, on the other hand, you could optimize this idea, for example using a thread pool, in which case you wouldn't have to spawn new threads all the time
Armen Tsirunyan
Using `Boost.Thread` can I put a thread to sleep and signal it when more data is available ?
nc3b
@n3cb: Yes, for example with a condition_variable. Basically if you read the documentation of boost::thread, you will get all the answers, including how to spawn/manipulate threads and how to do synchronization.
Armen Tsirunyan
"The classes condition_variable and condition_variable_any provide a mechanism for one thread to wait for notification from another thread that a particular condition has become true." This seems to be exactly what I need, thank you.
nc3b
+1  A: 

There are several examples provided by the boost documentation that describe what you are wanting to accomplish.

http://www.boost.org/doc/libs/1_44_0/doc/html/boost_asio/examples.html

look under the section titled timeouts for the examples.

diverscuba23
Could you please be more specific ? I am quite new to boost and a little guidance would help a lot.
nc3b
+1  A: 

Unless the work your handler does is very short-lived (unlikely in a real world application), you are going to want a producer/consumer queue to hand off the received data from your I/O thread(s) to your worker thraed(s) for further processing, so you can return from your handler asap.

There is a primer on producer/consumer using Boost.Thread here - written by the current author of the Boost Threads library, as a bonus.

Steve Townsend
Thank you, that looks great :)
nc3b
@nc3b - I cannot say enough good things about these parts of Boost.
Steve Townsend
+1  A: 

An extra thread(s) to handle the callback processing is a good idea. As mentioned above, having your callback push a message onto a thread safe queue and another thread consuming/processing the message works great.

Another threading scenario that may work for you is to just start additional threads on the io_service. These additional threads will make it possible to process several handlers at the same time.

const int max_threads = 5;
boost::asio::io_service ios;
boost::thread_group thread_group;

for (int i = 0 ; i < max_threads; ++i)
  thread_group.create_thread( boost::bind(&boost::asio::io_service::run, boost::ref(ios)) );

The correct solution really depends on what the application is doing. If this is a TCP connection and the messages need to be processed in sequential order consider using the producer/consumer queue. If the messages are independent of each other and do not require that they are processed in order then this approach is suitable as well.

If its a UDP connection then all bets are off anyway because the ordering of the received messages is not guaranteed.

skimobear
Thank you for your advice, I ended up with a producer/consumer model (as the messages are processed in sequential order).
nc3b