我通过选择std :: thread来使我的线程并发分配错误。我没有时间学习其他方法了。所以我希望你能在这里帮助我,我真的很困惑所有那些类型的互斥,承诺,期货等。缺乏各种文档/教程令人沮丧。 所以我希望3个线程(玩家)做同样的事情 - 选择2个随机数作为全局2-D数组的索引,如果单元格的值为0则设置它等于线程的Id,否则停止执行线程。在循环中执行此操作,直到只剩下一个线程。 我需要的是找到一种在每次(在下一次)迭代之后同步3个线程的方法,这样一个线程就不能在第50次迭代中,而另一个线程在第30次迭代时,即线程必须等待让所有其他人在继续前完成迭代。我需要某种障碍。 我尝试使用条件变量将线程置于睡眠状态,直到最后一个完成线程发出信号唤醒它们但我无法使其工作。 我的失败尝试被注释掉了:
std::mutex GridMutex, FinishMutex, LeftMutex;
int Grid[X][Y], Finished = 0, PlayersLeft = 3;
void Fight(int Id) {
int RandX, RandY, i = 0;
std::random_device rd; // access random device
std::mt19937 e(rd()); // seed the engine
std::uniform_int_distribution<int> r1(0, X-1);
std::uniform_int_distribution<int> r2(0, Y-1);
LeftMutex.lock(); // mutex on PlayersLeft
while (PlayersLeft != 1) {
++i;
/*std::call_once(flag, [Id, i](){*/std::cout << " Round " << i << " Left: " << PlayersLeft << '\n';/*});*/
LeftMutex.unlock();
// FinishMutex.lock();
// std::call_once(flag, [](){Finished = 0;});
// FinishMutex.unlock();
RandX = r1(e);
RandY = r2(e);
GridMutex.lock();
if (Grid[RandX][RandY] != Id) {
if (Grid[RandX][RandY] == 0) {
Grid[RandX][RandY] = Id;
std::cout << "i= "<< i << " Thread " << Id << " occupied cell " << RandX << RandY << '\n';
std::chrono::milliseconds sleepDuration(100);
std::this_thread::sleep_for(sleepDuration); //just to lock the grid for some time
GridMutex.unlock();
}
else {
GridMutex.unlock();
LeftMutex.lock();
--PlayersLeft;
LeftMutex.unlock();
break; //stop thread if cell occupied
}
}
//Wait for the others here
// FinishMutex.lock();
// ++Finished;
// if (Finished == 3) {
// FinishMutex.unlock();
// AllReady.notify_all();
// }
// else {
// FinishMutex.unlock();
// AllReady.wait(Lk, [](){return Finished == 3;});
// Lk.unlock();
// }
LeftMutex.lock();
}
}
int main() {
SetGrid();
std::thread t1(&Fight, 1);
std::thread t2(&Fight, 2);
std::thread t3(&Fight, 3);
t1.join();
t2.join();
t3.join();
GetGrid();
return 0;
}
我希望“call_once”中的表达式在每次迭代时只由一个线程(以先到者为准)执行,但很明显,这不是我想的那样,因为这会导致一些奇怪的行为。怎么做? 好吧,代码可能很丑,所有这些都应该放在类和方法之中,但我只需要让它工作无论多么原始。 提前谢谢!
答案 0 :(得分:1)
您可以使用std::atomic_int
和std::atomic_bool
(或std::atomic_flag
{/ 3}} atomic variables删除一些锁定。
接下来,不要自己进行锁定和解锁,而是使用RAII
包装器,例如std::lock_guard
。这将锁定指定的互斥锁,直到锁定对象本身被销毁(通常是当它超出范围时)。
现在,虽然使用这些东西会大大改善您的代码,但实际的逻辑错误非常简单:您不应该将常量3与playersLeft
进行比较。请注意,由于条件取决于此条件,因此无论何时更改此变量,您都必须发出信号。