Skip to content
Advertisement

`boost::asio` `async_resolve` hangs on Linux, what may be a reason?

I write complex TCP/IP client application that generates a lot of outgoing TCP connections. I try to use boost::asio as portable TCP/IP networking implementation in C++.

I found following issue. See the code:

int main(int argc, char *argv[])
{
    using namespace boost::asio;
    io_service io;
    thread ioThread([&io]()
    {
        while (true)
        {
            if (!io.run())
                this_thread::sleep_for(seconds(1));
        }
    });
    ioThread.detach();
    ip::tcp::resolver r(io);
    ip::tcp::resolver::query q("www.boost.org", "80");
    atomic<bool> done(false);
    r.async_resolve(q, [&done](const boost::system::error_code& error, ip::tcp::resolver::iterator iterator)
    {
        if (error)
            wprintf(W("Error!rn"));
        else
        {
            ip::tcp::resolver::iterator end;
            while (iterator != end)
            {
                ip::tcp::endpoint endpoint = *iterator++;
                std::cout << endpoint << std::endl;
            }
        }
        done.store(true);
    });
    while (!done.load())
        this_thread::sleep_for(seconds(1));
    return 0;
}

This code runs background thread to execute io_service::run method. It is supposed that we’ll have multiple sockets that use this io_service to perform asyncrhonous operations.

On Windows (Visual Studio 2013 x64) this code runs well and prints endpoint address.

On CentOS Linux 6 with boost 1.60 and clang 3.4.2 it hangs.

Are there any ideas why does async_resolve never completes?

Advertisement

Answer

I believe the problem is that your thread function does not reset the boost::asio::io_service instance. The documentation says:

[reset()] must be called prior to any second or later set of invocations of the run(), run_one(), poll() or poll_one() functions when a previous invocation of these functions returned due to the io_service being stopped or running out of work.

In your program, the boost::asio::io_service instance returns because it runs out of work, so you can’t call it again (i.e. on the next loop iteration) without calling reset() first.

There is a race condition in your program that will let it work in some cases and not work in some cases. If the resolver operations are enqueued in time for the first time run() is invoked then it will work. If not then it won’t work. This should explain why it works on one OS but not another.

One more note not directly related to your problem is that your thread function calling run() in a loop is somewhat awkward. If you want to control the duration of run(), using io_service::work may be a better approach.

User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement