0

I am already working long on this without success.

Imagine you have your main function some sort like this:

bool running = true;
int i = 0;
//waitHandler();
while(running)
    i++;

Now I would like to add and call a timer, which sets running to false, when it expires.

void waitHandler(){ 

    boost::asio::io_service timerService;

    //create and bind the timer
    boost::asio::deadline_timer timer(timerService,
    boost::posix_time::milliseconds(2000));
    timer.wait();

    running = true;
    cout<<"WaitHandler triggered"<<endl;
}

Of course this does not work (when u uncomment the comment above), since the timer will block the main thread. What to do, if I would want to have this functionality without blocking the main function.

EDIT:

//transfer some error message
void set_result(boost::system::error_code* a, boost::system::error_code b,deadline_timer &timer)
  {
     a->assign(b.value(),b.category());
  } 


 template<class SOCKET>
 void read_with_timeout(SOCKET & sock, unsigned int delay,
     const asio::mutable_buffers_1& buffers)
  {       
      //create error messages
      boost::system::error_code timer_result; 
      boost::system::error_code read_result; 

      //initialize timer
      deadline_timer timer(sock.get_io_service());        
      timer.expires_from_now(boost::posix_time::milliseconds(delay));
      timer.async_wait(boost::bind(set_result, &timer_result, _1,boost::ref(timer)));       

      //initialize receive mechanism
      sock.async_receive(buffers, boost::bind(set_result, &read_result, _1,boost::ref(timer)));    
      sock.get_io_service().reset();

      //should run for one handler
      while (sock.get_io_service().run_one())    
      {      
          if (read_result.value()==0){ //zero stands for, that the message was received properly.            
              timer.cancel();
              //cout<<"Message received: => Timer cancelled => RETURN!"<<endl;
              return;
          }

          if(timer.expires_from_now().total_milliseconds() <=0){                
              sock.cancel();                
              //cout<<"Timeout => Socket cancelled => RETURN!"<<endl;         
              return;
          }
      }   
 } 

As said this almost shows the wished behavior, but there are some questions to it:

  1. Why by even using run_one, both the handler for the timer and the one for the receive can be fired
  2. Why does receive also fire, when 0 bytes are received. For me that sounds like nothing is received and the function is supposed to wait?
  3. Is this the right way to do it - as I said I want to receive or timeout. (like pinging)

Actually the pakets are received in wrong order as they appeared in Wireshark - I guess it has something to do with async_receive, which does not really wait for a incoming message, but just takes what is in the buffer before the function call.

What to do?

Sam Miller
  • 23,808
  • 4
  • 67
  • 87
Vladimir S.
  • 450
  • 2
  • 10
  • 23

4 Answers4

4

You are making this much more complex than it needs to be. There are piles of questions on this site dealing with timeouts, and a fantastic example on the Boost.Asio website. The comment from the async_tcp_client example has an excellent ASCII diagram explaining this scenario

// This class manages socket timeouts by applying the concept of a deadline.
// Some asynchronous operations are given deadlines by which they must complete.
// Deadlines are enforced by an "actor" that persists for the lifetime of the
// client object:
//
//  +----------------+
//  |                |
//  | check_deadline |<---+
//  |                |    |
//  +----------------+    | async_wait()
//              |         |
//              +---------+
//
// If the deadline actor determines that the deadline has expired, the socket
// is closed and any outstanding operations are consequently cancelled.
//
// Connection establishment involves trying each endpoint in turn until a
// connection is successful, or the available endpoints are exhausted. If the
// deadline actor closes the socket, the connect actor is woken up and moves to
// the next endpoint.
//
//  +---------------+
//  |               |
//  | start_connect |<---+
//  |               |    |
//  +---------------+    |
//           |           |
//  async_-  |    +----------------+
// connect() |    |                |
//           +--->| handle_connect |
//                |                |
//                +----------------+
//                          :
// Once a connection is     :
// made, the connect        :
// actor forks in two -     :
//                          :
// an actor for reading     :       and an actor for
// inbound messages:        :       sending heartbeats:
//                          :
//  +------------+          :          +-------------+
//  |            |<- - - - -+- - - - ->|             |
//  | start_read |                     | start_write |<---+
//  |            |<---+                |             |    |
//  +------------+    |                +-------------+    | async_wait()
//          |         |                        |          |
//  async_- |    +-------------+       async_- |    +--------------+
//   read_- |    |             |       write() |    |              |
//  until() +--->| handle_read |               +--->| handle_write |
//               |             |                    |              |
//               +-------------+                    +--------------+
//
// The input actor reads messages from the socket, where messages are delimited
// by the newline character. The deadline for a complete message is 30 seconds.
//
// The heartbeat actor sends a heartbeat (a message that consists of a single
// newline character) every 10 seconds. In this example, no deadline is applied
// message sending.
//

You should strive to achieve a similar design in your application. There is no need to bumble around by writing a read_with_timeout() function like you have posted in your question. Using async_read(), async_write(), and async_wait() will be enough to give you the desired functionality.

I think part of your confusion arises over threading. Don't think about it, understand the basic concepts first. You will want to use a single thread (the one invoking main()) and a single io_service to start. After that, you can explore more advanced concepts. If you're trying to integrate this code into a larger application, that is a different question entirely.

Studying the proactor design pattern may be helpful to you as well.

Community
  • 1
  • 1
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • Hi thanks for this answer. I will check this out. It sounds very interesting. – Vladimir S. Oct 15 '12 at 13:35
  • Actually the links you reference, do reference very similar code to the one I used using the read_with_timeout function. (especially in piles of questions) – Vladimir S. Oct 22 '12 at 11:39
  • The boost example was removed. I am pretty sure it was there 2 months ago. – Tomáš Zato Nov 26 '15 at 16:13
  • They put the sample code under cpp03 subdirectory: http://www.boost.org/doc/libs/1_60_0/doc/html/boost_asio/example/cpp03/timeouts/async_tcp_client.cpp I fixed it in the answer. – ta55e Apr 20 '16 at 08:21
1

You can either execute io_service::run in a separate thread (and somehow synchronize the access to running) or pump the io_service loop manually within your while loop, using run_one()/poll()/poll_one() - whatever is appropriate in your case.

Igor R.
  • 14,716
  • 2
  • 49
  • 83
0

I have found out some sort of solution. I am ok with it even though there are things I do not understand.

//transfer some error message
void set_result(boost::system::error_code* a, boost::system::error_code b,deadline_timer &timer)
  {
     a->assign(b.value(),b.category());
  } 


 template<class SOCKET>
 void read_with_timeout(SOCKET & sock, unsigned int delay,
     const asio::mutable_buffers_1& buffers)
  {       
      //create error messages
      boost::system::error_code timer_result; 
      boost::system::error_code read_result; 

      //initialize timer
      deadline_timer timer(sock.get_io_service());        
      timer.expires_from_now(boost::posix_time::milliseconds(delay));
      timer.async_wait(boost::bind(set_result, &timer_result, _1,boost::ref(timer)));       

      //initialize receive mechanism
      sock.async_receive(buffers, boost::bind(set_result, &read_result, _1,boost::ref(timer)));    
      sock.get_io_service().reset();

      //should run for one handler
      while (sock.get_io_service().run_one())    
      {      
          if (read_result.value()==0){ //zero stands for, that the message was received properly.            
              timer.cancel();
              //cout<<"Message received: => Timer cancelled => RETURN!"<<endl;
              return;
          }

          if(timer.expires_from_now().total_milliseconds() <=0){                
              sock.cancel();                
              //cout<<"Timeout => Socket cancelled => RETURN!"<<endl;         
              return;
          }
      }   
 } 

This actually works for my case and was taken from http://lists.boost.org/Archives/boost/2007/04/120339.php referenced by this thread: How to set a timeout on blocking sockets in boost asio?

I just adapted it to Boost 1.51.

A few things are still obscured to me like e.g.

  • io_service.run_one actually still fires more event handlers even though it is supposed to only fire one.
  • Also there are events from the timer which do not at all interest me. I just want to catch the timeout and not other stuff. (I don know why there is other stuff)

In any case my problem was solved so far.

Community
  • 1
  • 1
Vladimir S.
  • 450
  • 2
  • 10
  • 23
  • 1
    why jump through all these hoops to achieve a timeout with a blocking socket? Just use async read and write. – Sam Miller Oct 06 '12 at 15:33
  • async read and write just blocks, but the upper example seems to work! – Vladimir S. Oct 08 '12 at 08:39
  • @sam miller: Could you be a bit more precise and explain me your idea a bit more. I really do not know, what the right way is. I also don understand the sense of async without threading. Do i need threads? – Vladimir S. Oct 08 '12 at 15:55
-1

You have to spawn the timer on its own thread and then make sure that you protect the running variable from concurrent access.

Liron
  • 2,012
  • 19
  • 39
  • Do I always need a thread independent of using either an synchronous timer like in the example above or an async_wait? – Vladimir S. Oct 04 '12 at 12:46
  • It depends on what you're trying to do. If you're trying to do work for a particular amount of time, you could also get the current time at the beginning of the loop, and every time through the loop you can check how much time has elapsed since that start time. After elapsedTime > X you can break out of the loop. But if you want a program to remain responsive while it is doing work in the background, you need to use threads. The async_wait is creating the thread for you, so you are creating a method for the async_wait to call after the wait has finished. – Liron Oct 04 '12 at 12:55
  • So this means, that actually e.g. timer.async_wait(waitHandler) (do not mind the syntax) should create a thread by itself and thus not block the main thread? – Vladimir S. Oct 04 '12 at 13:50
  • 2
    @Byron-Lim Timothy Steffan `async_wait` does not create threads, it just initiates an async.operations. The completion handler of this operation gets called on `io_service` thread, which is blocked in your example. So using `async_wait` won't help you, until you execute `io_service::run` in another thread. – Igor R. Oct 04 '12 at 14:01