繁体   English   中英

C ++十六进制游戏:使用多个线程时模拟不起作用

[英]c++ hex game: simulation not working when using multiple threads

我正在为HEX游戏实现一个蒙特卡洛模拟器(这是我正在遵循的Coursera类的作业)。 我有一块板,上面放着有颜色的岩石。 白色和黑色表示该位置已使用,灰色表示该位置仍然可用。

我有一个Player,它是一个抽象类,我为人和计算机的玩家指定了不同的名称。 看起来像这样:

template <class Board>
class AiPlayer : public Player<Board> {
    using Player<Board>::_color;
    using Player<Board>::_board_ptr;
    std::mutex board_mutex;
    public:
        void simulate (const std::pair<int, int>&, const Color, std::vector<double>& wins);
        AiPlayer(const Color c):Player<Board>(c) {}
        AiPlayer(const Color c, std::shared_ptr<Board> board):Player<Board>(c, board) {}
        virtual void play();
};

template <class Board>
void AiPlayer<Board>::play()
{
    //each thread start from a different starting point
    std::array<std::thread, _N_THREADS> threads;
    std::size_t N = _board_ptr->X()*_board_ptr->Y();
    Color opponent_color = _color == Color::WHITE ? Color::BLACK : Color::WHITE;
    std::vector<double> wins(N, 0);


    int t = 0;
    for (int i = 0; i < _board_ptr->X(); ++i) {
        for (int j = 0; j < _board_ptr->Y(); ++j) {
            if (_board_ptr->rock(i,j).color() == Color::GREY) {
                auto start_position = std::make_pair(i,j);
                //std::cout << t <<": starting simulation from " << start_position << std::endl;
                threads[t++] =std::thread(&AiPlayer<Board>::simulate,
                        this, std::ref(start_position),
                        opponent_color, std::ref(wins));
                if (t == _N_THREADS ||
                    (i == (_board_ptr->X() - 1) && j == (_board_ptr->Y() - 1))) {
                    for (int tt = 0; tt < t; ++tt) {
                        threads[tt].join();
                    }
                    //std::cout << "joining threads" << std::endl;
                    t = 0;
                }
            }
        }
    }
    double max_val = 0; size_t max_idx = 0;
    for(std::size_t i = 0; i < wins.size(); ++i) {
        if(max_val < wins[i]) {
            max_val = wins[i];
            max_idx = i;
        }
    }
    auto i = max_idx/_board_ptr->Y();
    auto j = max_idx % _board_ptr->Y();
    _board_ptr->add_rock(i, j, Rock(_color));
    std::cout << std::make_pair(i,j) << ": " <<
        _board_ptr->rock(i, j) << std::endl;
    return;
}


template <class Board>
void AiPlayer<Board>::simulate (const std::pair<int, int>& start,
        const Color opponent_col, std::vector<double>& wins)
{
    Board local_board(*_board_ptr);

    local_board.add_rock(start.first, start.second, Rock(_color));
    assert(local_board.rock(start.first, start.second).color() != Color::GREY);

    std::size_t N = local_board.n_free();
    using std::vector;
    vector<std::pair<int, int>> free_pos(N);
    vector<Color> free_pos_color(N);
    for (int i = 0, k = 0; i < local_board.X(); ++i) {
        for(int j = 0; j < local_board.Y(); ++j) {
            if (local_board.rock(i,j).color() == Color::GREY) {
                assert(!(i == start.first && j == start.second));
                free_pos[k] = std::make_pair(i,j);
                free_pos_color[k] = k & 0x01 ? _color : opponent_col;
                ++k;
            }
        }
    }
    assert(local_board.rock(start.first, start.second).color() != Color::GREY);

    //generate random permutation of colors for the free postions
    std::random_device rd;
    std::mt19937 g(rd());
    //int wins = 0;
    for (int i = 0; i < 1000; ++i) {
        std::shuffle(free_pos_color.begin(), free_pos_color.end(), g);
        for (std::size_t k = 0; k < free_pos.size(); ++k) {
            assert(!(free_pos[k].first == start.first &&
                        free_pos[k].second == start.second));
            local_board.add_rock(free_pos[k].first, free_pos[k].second, 
                    Rock(free_pos_color[k]));
        }
        //clean up
        auto l = start.first*local_board.Y() + start.second;
        assert(local_board.rock(start.first, start.second).color()  != Color::GREY);
        wins[l] += local_board.winner() == _color ? 1 : 0;
        assert(local_board.rock(start.first, start.second).color()  != Color::GREY);
        for (std::size_t k = 0; k < free_pos.size(); ++k) {
            assert(!(free_pos[k].first == start.first &&
                        free_pos[k].second == start.second));
            local_board.add_rock(free_pos[k].first, free_pos[k].second, 
                    Rock(Color::GREY));
        }
    }
    //remove initial move
    assert(local_board.rock(start.first, start.second).color()  != Color::GREY);
    local_board.add_rock(start.first, start.second, Rock(Color::GREY));

}

如果是单线程,则没有问题。 当我开始使用大量线程时,出现一些奇怪的错误。 例如,模拟中的断言随机失败。 我不明白问题出在哪里,因为全局变量_board_ptr仅由线程读取(我也尝试过锁定,但无济于事),并且wins仅针对每个线程正在模拟的特定起始位置进行更新。

看来问题出在局部变量上。 例如,当我检查local_board元素的颜色时,颜色不是应该的,或者free_pos所保持的对的坐标等于起始位置。 我有几次相同的断言插入代码,有时,其中之一随机失败。

这些变量的寿命是否不限于线程本身的寿命? 关于我在做什么错的任何想法吗?

非常感谢!

我知道了。 我通过引用传递了start_pos ,这被主线程更改了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM