簡體   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