[英]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.