Search code examples
boostjava-native-interfaceboost-asio

Deadline_timer not firing while calling async_connect in a loop


Trying to use deadlinetimer in a similar way as suggested by boost documentation: https://www.boost.org/doc/libs/1_47_0/doc/html/boost_asio/example/timeouts/blocking_tcp_client.cpp

Code: JNI thread:

HttpClient client(io_service);
client.doAsyncOperation()
io_service.run()

HttpClient:

 doAsyncOperation(){
     timer_.expires_from_now(boost::posix_time::seconds(10));
     mSocket.async_connect( endpoint,
                       boost::bind(&HttpClient::handle_connect_async, this,
                                   boost::asio::placeholders::error)

}

void HttpClient::check_deadline(){
if (timer_.expires_at() <= deadline_timer::traits_type::now())
{
    mSocket.cancel();
}else{

   timer_.async_wait(boost::bind(&SchamanHttpClient::check_deadline, this));
}

}

Update: Fix: run io_service on a separate thread

So, inside the JNI thread:

 HttpClient client(io_service);
 client.doAsyncOperation()
 boost::thread t(boost::bind(&boost::asio::io_service::run,&io_service));
io_service.run();
t.join();

HttpClient:

void HttpClient::check_deadline(){
if (timer_.expires_at() <= deadline_timer::traits_type::now())
{
    mSocket.cancel();
    io_service.stop();
}else{

   timer_.async_wait(boost::bind(&SchamanHttpClient::check_deadline, this));
}

Solution

  • None of these examples are that way anymore. For a long time much nicer interfaces exist. Definitely look into these samples in a recent version of boost:

    libs/asio/example/cpp03/timeouts/blocking_tcp_client.cpp
    libs/asio/example/cpp11/timeouts/blocking_tcp_client.cpp
    

    The check_deadline() is never called again. What is wrong?

    Many possibilities:

    • no operation times out (10s is a lot)
    • you're not running the io_service (if you don't poll/run tasks, nothing will happen)
    • the timer got destructed

    However, the most likely thing I think might confuse you is: when the timer has expired (timed out) it will set it to never expire again:

    void HttpClient::check_deadline() {
        if (timer_.expires_at() <= deadline_timer::traits_type::now()) {
            mSocket.cancel();
            timer_.expires_at(boost::posix_time::pos_infin);
        }
        timer_.async_wait(boost::bind(&HttpClient::check_deadline, this));
    }
    

    In short, the whole pattern behind all these 'blocking IO with timeouts' is that you set a timeout before every operation.