Член std :: future, предотвращающий выход boost :: shared_ptr из области видимости - PullRequest
0 голосов
/ 14 января 2019

У меня есть функция, которая создает новый объект моста и сохраняет его как boost :: shared_ptr:

bool proxy::bridge::acceptor::accept_connections() {
    try {
        session_ = boost::shared_ptr<bridge>(new bridge(io_service_));

        acceptor_.async_accept(session_->downstream_socket(),
            boost::bind(&acceptor::handle_accept,
                this, boost::asio::placeholders::error));
    }
    catch (std::exception& e) {
        std::cerr << e.what() << std::endl;
        return false;
    }

return true;
}

void proxy::bridge::acceptor::handle_accept(const boost::system::error_code& error) {
    if (!error) {
        session_->local_connect();
        if (!accept_connections()) {
        }
    }
    else {
        std::cerr << error.message() << std::endl;
    }
}

В классе моста есть переменная std :: future, определенная в заголовке и инициализированная в методе класса моста:

//proxy.h
std::mutex add_data_lock;
std::vector<int> global_resource_protected_by_lock;

class proxy {
    //...
    class bridge {
        //...
        std::future<void> f_read;
    };

    class acceptor {
         //...
    };
};

//proxy.cpp
void proxy::bridge::read(const boost::system::error_code& error, const size_t& bytes_transferred) {
    if (!error) {
        if (f_read.valid()) { f_read.wait(); }
        f_read = std::async(std::launch::async, std::bind(&proxy::bridge::handle_add_data, shared_from_this(), bytes_transferred));
    }
    else {
        close();
    }
}

void proxy::bridge::handle_add_data(const size_t& bytes_transferred) {
    add_data_lock.lock();
    //do work here
    add_data_lock.unlock();
}

void proxy::bridge::close() {
    //this is called when this object is no longer useful (ie. connection closed)

    if (f_read.valid()) { f_read.wait(); }

    //other closing functions...
}

Метод read () вызывается неоднократно - цель состоит в том, чтобы вызывать handle_add_data () асинхронно и выполнять работу между циклами read ().

Однако динамически созданный объект моста никогда не удаляется даже после закрытия сокета (процесс занимает все больше и больше памяти).

Если я заменю асинхронный вызов и будущее прямым вызовом функции handle_add_data (), все будет правильно освобождено при вызове close ().

Если я перемещу будущее f_read за пределы класса как статическую переменную с областью видимости файла, то все также будет освобождено должным образом, но иногда я получаю сообщения об ошибке «уничтожение мьютекса во время занятости».

Если я не назначаю асинхронный вызов чему-либо, то он блокируется при выходе из области действия функции и лишает цели его использования.

Что мне делать, чтобы динамически созданные объекты-мосты правильно удалялись после вызова close ()?

Извините за запутанный код - я сжал его как можно лучше, чтобы проиллюстрировать проблему.

1 Ответ

0 голосов
/ 14 января 2019

Ваш bind держит на shared_ptr дольше, чем нужно. Вы можете изменить его, чтобы явно освободить захваченный указатель, когда это будет сделано.

f_read = std::async(std::launch::async, [=, self = shared_from_this()]() mutable { self->handle_add_data(bytes_transferred); self = nullptr; });

До C ++ 14 вам нужно выполнить инициализацию как локальный объект, который захватывается

auto self = shared_from_this();
f_read = std::async(std::launch::async, [=]() mutable { self->handle_add_data(bytes_transferred); self = nullptr; });
...