boost::asio::io_service::strand不肯走

boost::asio::io_service::strand refuses to go away

我正在使用 strand 在一些 object 中序列化某些处理。然而,当 object 消失时, strand 元素以某种方式拒绝消失。就像炼狱中的灵魂一样,它设法活在内存中,并导致内存使用量随着时间的推移而增加。我已经成功地在示例代码中复制了这个问题。

我正在创建 5 个家庭,每个家庭有一个 parent 和一个 child。 parent object 包含 child 和一个链 object 以确保以串行方式进行处理。每个家庭都被分配了 3 个处理任务,并且它们以正确的顺序执行,而不管它们 运行 在哪个线程上。在 object 创建和处理之前和之后,我正在 VC++ 中拍摄内存堆快照。快照比较显示,即使在 Parent 和 Child object 被销毁后,单独的链仍然存在。

如何确保链 object 被销毁?与示例程序不同,我的应用程序 运行s 多年没有关闭。我将在一个月内陷入数百万个僵尸链object。

#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio/strand.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/bind.hpp>
#include <boost/make_shared.hpp>
#include <boost/asio/yield.hpp>
#include <boost/log/attributes/current_thread_id.hpp>
#include <iostream>

boost::mutex mtx;

class Child : public boost::noncopyable, public boost::enable_shared_from_this<Child>
{
    int _id;
public:
    Child(int id) : _id(id) {}
    void process(int order)
    {
        boost::this_thread::sleep_for(boost::chrono::seconds(2));
        boost::lock_guard<boost::mutex> lock(mtx);
        std::cout << "Family " << _id << " processing order " << order << " in thread " << std::hex << boost::this_thread::get_id() << std::endl;
    }
};

class Parent : public boost::noncopyable, public boost::enable_shared_from_this<Parent>
{
    boost::shared_ptr<Child> _child;
    boost::asio::io_service::strand _strand;

public:
    Parent(boost::asio::io_service& ioS, int id) : _strand(ioS)
    {
        _child = boost::make_shared<Child>(id);
    }

    void process()
    {
        for (int order = 1; order <= 3; order++)
        {
            _strand.post(boost::bind(&Child::process, _child, order));
        }
    }
};

int main(int argc, char* argv[])
{
    boost::asio::io_service ioS;
    boost::thread_group threadPool;
    boost::asio::io_service::work work(ioS);

    int noOfCores = boost::thread::hardware_concurrency();
    for (int i = 0; i < noOfCores; i++)
    {
        threadPool.create_thread(boost::bind(&boost::asio::io_service::run, &ioS));
    }

    std::cout << "Take the first snapshot" << std::endl;
    boost::this_thread::sleep_for(boost::chrono::seconds(10));

    std::cout << "Creating families" << std::endl;
    for (int family = 1; family <= 5; family++)
    {
        auto obj = boost::make_shared<Parent>(ioS,family);
        obj->process();
    }
    std::cout << "Take the second snapshot after all orders are processed" << std::endl;

    boost::this_thread::sleep_for(boost::chrono::seconds(60));
    return 0;
}

输出如下所示:

Take the first snapshot
Creating families
Take the second snapshot after all orders are processed
Family 3 processing order 1 in thread 50c8
Family 1 processing order 1 in thread 5e38
Family 4 processing order 1 in thread a0c
Family 5 processing order 1 in thread 47e8
Family 2 processing order 1 in thread 5f94
Family 3 processing order 2 in thread 46ac
Family 2 processing order 2 in thread 47e8
Family 5 processing order 2 in thread a0c
Family 1 processing order 2 in thread 50c8
Family 4 processing order 2 in thread 5e38
Family 2 processing order 3 in thread 47e8
Family 4 processing order 3 in thread 5e38
Family 1 processing order 3 in thread 50c8
Family 5 processing order 3 in thread a0c
Family 3 processing order 3 in thread 46ac

我在创建系列之前拍摄了第一个堆快照。在打印完所有 15 行(5 个家庭 X 3 个任务)后几秒钟,我拍摄了第二张快照。堆比较显示如下:

所有的Parent和Childobject都走了,但是所有的5股object都活着在...

编辑:对于那些不理解 shared_ptr 的人,object 不会在循环结束时死掉。由于 child 的引用已传递给 3 个流程任务,因此至少 child 过着迷人的生活,直到完成给定家庭的所有任务。清除所有引用后,Child object 将死亡。

这是设计使然。一条链使用一个互斥锁池,该互斥锁一直存在到 io_service 死亡。

但池大小目前限制为 193

所以你不应该看到超过 193 个闲逛的人。另见问题 #259.