The code below is intended to do the following: I have a resolver object which wraps boost asio. The resolver object holds the io service and a worker so the io service run function never returns. As long as the resolver object is alive, async requests can be made. When the resolver objects goes out of scope and there are still requests in the queue, I want to finish all and the resolver object gets destroyed.
In this case there is no handler called at all and I don't know why. I think there might be a problem with the shared pointers and some dependency cycle. Running with valgrind
reports "possibly lost memory".
Any ideas how to make this working so the resolver object stays alive until all work is done?
#include <boost/asio.hpp>
#include <memory>
#include <thread>
#include <functional>
#include <string>
#include <iostream>
struct Resolver : public std::enable_shared_from_this<Resolver> {
boost::asio::io_service io_service;
std::unique_ptr<boost::asio::io_service::work> work;
std::unique_ptr<std::thread> iothread;
struct Query : public std::enable_shared_from_this<Query>{
std::shared_ptr<Resolver> service;
boost::asio::ip::tcp::resolver resolver;
boost::asio::ip::tcp::resolver::query query;
std::function<void(boost::asio::ip::tcp::resolver::iterator &)> handler;
Query(std::shared_ptr<Resolver> res, std::function<void(boost::asio::ip::tcp::resolver::iterator &)> handler, const std::string &name) : resolver(res->io_service), query(name, ""), handler(handler) {
service = res;
}
void start() {
auto self = shared_from_this();
resolver.async_resolve(query, [self](const boost::system::error_code& ec, boost::asio::ip::tcp::resolver::iterator iterator){
self->handler(iterator);
});
}
};
Resolver() {
work.reset(new boost::asio::io_service::work(io_service));
iothread.reset(new std::thread(std::bind(&Resolver::io, this)));
}
~Resolver() {
std::cout << "Resolver destroyed" << std::endl;
work.reset();
iothread->join();
}
void io() {
io_service.run();
}
void asyncResolve(const std::string &name, std::function<void(boost::asio::ip::tcp::resolver::iterator &)> fn) {
auto query = std::make_shared<Query>(shared_from_this(), fn, name);
query->start();
}
};
void test(boost::asio::ip::tcp::resolver::iterator it) {
std::cout << "Test" << std::endl;
std::cout << it->endpoint().address().to_string() << std::endl;
}
int main(int argc, const char **argv) {
auto res = std::make_shared<Resolver>();
res->asyncResolve("stackoverflow.com", &test);
res->asyncResolve("stackoverflow.com", &test);
res->asyncResolve("stackoverflow.com", &test);
res->asyncResolve("stackoverflow.com", &test);
res->asyncResolve("stackoverflow.com", &test);
}