STD ::列表和垃圾收集算法

std::list and garbage Collection algorithm

本文关键字:算法 列表 STD      更新时间:2023-10-16

我有一台服务器,该服务器应要求将2个玩家放在一起,并在新线程中启动游戏Game

struct GInfo {Game* game; std::thread* g_thread};
while  (true) {
    players_pair = matchPlayers();
    Game* game = new Game(players_pair);
    std::thread* game_T = new std::thread(&Game::start, game);
    GInfo ginfo = {game, game_T}
    _actives.push_back(ginfo);    // std::list
}

我正在写一个在另一个线程中运行的"垃圾收集器",以清洁终止游戏的内存。

void garbageCollector() {
    while (true) {
        for (std::list<Ginfo>::iterator it = _actives.begin(); it != _actives.end(); ++it) {
            if (! it->game->isActive()) {
                delete it->game; it->game = nullptr;
                it->g_thread->join();
                delete it->g_thread; it->g_thread = nullptr;
                _actives.erase(it);
            }
        }
        sleep(2);
    }
}

这会产生一个segfault,我怀疑这是因为_active.erase(it)在迭代循环中。为了进行故障排除,我将_actives制作为std::vector(而不是std::list),并应用了相同的算法,但是使用索引而不是迭代器,它可以正常工作。

有办法解决吗?

算法,数据结构使用良好吗?有更好的方法来制作垃圾收集?

帮助您表示感谢!

如果您查看了擦除方法的文档,则将迭代器返回到删除的文档。

使用的方法是将返回的值分配给您的迭代器。

for (std::list<Ginfo>::iterator it = _actives.begin(); it != _actives.end();) {
    if (! it->game->isActive()) {
        delete it->game; it->game = nullptr;
        it->g_thread->join();
        delete it->g_thread; it->g_thread = nullptr;
        it = _actives.erase(it);
    }
    else {
        ++it;
    }
}

由于从erase拾取返回值将迭代器推进到下一个元素,因此我们必须确保在发生这种情况时不要递增迭代器。

在不相关的注释上,以下划线开头的变量名称通常保留给编译器的内部,应在您自己的代码中避免。

有更好的方法来做垃圾收集?

是的,请勿使用new,delete或动态内存alltodereth:

struct Players{};
struct Game{
    Game(Players&& players){}
};
struct GInfo {
    GInfo(Players&& players_pair):
        game(std::move(players_pair)),g_thread(&Game::start, game){}
    Game game; 
    std::thread g_thread;
};
std::list<GInfo> _actives;
void someLoop()
{
    while  (true) {
        GInfo& ginfo = _actives.emplace_back(matchPlayers());
    }
}
void garbageCollector() {
    while (true) {
        //Since C++20
        //_active.remove_if([](GInfo& i){ return !i.game.isActive();});
        //Until C++20
        auto IT =std::remove_if(_actives.begin(),_actives.end(),
                      [](GInfo& i){ return !i.game.isActive();});
        _active.erase(IT,_active.end());
        //
        sleep(2);
    }
}

可能有一些错别字,但这就是想法。