【问题标题】:Member std::future preventing boost::shared_ptr from going out of scope成员 std::future 防止 boost::shared_ptr 超出范围
【发布时间】:2019-01-14 09:44:09
【问题描述】:

我有一个函数可以创建一个新的桥对象并将其存储为 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() 循环之间执行工作。

但是,即使在套接字关闭后,动态创建的桥对象也不会被删除(进程占用越来越多的内存)。

如果我将异步调用和 future 替换为对 handle_add_data() 的直接函数调用,则在调用 close() 时会正确释放所有内容。

如果我将 f_read 未来作为具有文件作用域的静态变量移到类外部,那么所有内容也会被正确释放,但有时我会收到“忙时销毁互斥锁​​”错误。

如果我没有将异步调用分配给任何东西,那么它会在超出函数范围时阻塞并破坏使用它的目的。

我应该怎么做才能在调用 close() 后正确删除动态创建的桥对象?

抱歉,代码混乱 - 我尽可能地对其进行压缩以说明问题。

【问题讨论】:

  • 为什么是boost::shared_ptr 而不是std::shared_ptr?您使用std::future 意味着您的编译器支持c++11,所以应该没有问题。
  • 这是我拼凑起来并写了一半的科学怪人代码,所以我并没有真正考虑过它。为了将来参考,std::shared_ptr 是否比 boost 的实现更可取?
  • 如果 std 实现在所有目标平台上都可用(除了非常罕见的例外,例如正则表达式),那么它们总是比 boost 更可取。
  • 我明白了!我会交换它们并记住这一点以备将来使用。

标签: c++ boost-asio shared-ptr stdasync


【解决方案1】:

您的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; });

【讨论】:

  • 这不需要是一个可变的 lambda 吗? (另外,有些人会说self.reset()更清晰,我目前对此感觉不强烈)
  • 发布!=重置。这是哪一个?
  • @rubenvb 这是口语用法,大致是“放弃指针对象的(共享)所有权”。
  • @Caleth 在 shared_ptr 上调用 reset 会删除指针。 assigning nullptr 也是如此。这不是release 所做的。您的口语用法完全不正确。
  • @rubenvb 仅当它是last owner,这是这里的意图
猜你喜欢
  • 1970-01-01
  • 2015-01-09
  • 2020-08-11
  • 1970-01-01
  • 2021-05-14
  • 1970-01-01
  • 2011-08-30
  • 2010-11-22
  • 2016-02-17
相关资源
最近更新 更多