简体   繁体   English

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

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

I am implementing a monte carlo simulator for the HEX game (it is an assignment of a Coursera class I am following). 我正在为HEX游戏实现一个蒙特卡洛模拟器(这是我正在遵循的Coursera类的作业)。 I have a board, that holds the rocks that have a color. 我有一块板,上面放着有颜色的岩石。 WHITE and BLACK color means that the position is used, GREY that it is still available. 白色和黑色表示该位置已使用,灰色表示该位置仍然可用。

I have a Player that is an abstract class that I specify for human and computers players differently. 我有一个Player,它是一个抽象类,我为人和计算机的玩家指定了不同的名称。 It looks something like this: 看起来像这样:

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));

} }

When it is single thread, there is no issues. 如果是单线程,则没有问题。 When I start using a larger number of threads, I get some weird error. 当我开始使用大量线程时,出现一些奇怪的错误。 For instance, the asserts in simulate randomly fail. 例如,模拟中的断言随机失败。 I do not understand what is the problem, since the global variable _board_ptr is only read by the threads (I tried also to lock, but it does not help) and wins is update only for the specific start position each thread is simulating. 我不明白问题出在哪里,因为全局变量_board_ptr仅由线程读取(我也尝试过锁定,但无济于事),并且wins仅针对每个线程正在模拟的特定起始位置进行更新。

It seems that problem is with the local variables. 看来问题出在局部变量上。 For instance, when I check for the color of the elements of the local_board it is not what it should be or the coordinates of the pair held by free_pos are equal to the starting position. 例如,当我检查local_board元素的颜色时,颜色不是应该的,或者free_pos所保持的对的坐标等于起始位置。 I have several time the same asserts into the code, and sometime, one of the randomly fails. 我有几次相同的断言插入代码,有时,其中之一随机失败。

Is not the life of these variable limited to the life of the thread itself? 这些变量的寿命是否不限于线程本身的寿命? Any idea about what am I doing wrong? 关于我在做什么错的任何想法吗?

Thanks a lot! 非常感谢!

I figure it out. 我知道了。 I was passing start_pos by reference and this was changed by the main thread. 我通过引用传递了start_pos ,这被主线程更改了。

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

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