循环内的 C++ std::thread 同步

标签 c++ multithreading c++11 synchronization

我错误地选择了 std::thread 来进行线程并发分配。我没有时间学习其他方法。所以我希望你能在这里帮助我,我真的很困惑所有这些类型的互斥体、 promise 、 future 等。缺乏多样化的文档/教程令人沮丧。 所以我希望 3 个线程(玩家)做同样的事情——选择 2 个随机数作为全局二维数组的索引,如果单元格的值为 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”中的表达式在每次迭代中仅由一个线程(以先到者为准)执行,但显然这不是我想的那样,因为这会导致一些奇怪的行为。怎么做? 好的,代码可能很丑陋,所有这些都应该放在类和方法或其他东西中,但无论多么原始,我只需要让它工作。 提前致谢!

最佳答案

您可以使用 atomic variables 移除一些锁像 std::atomic_intstd::atomic_bool(或 std::atomic_flag

接下来,不要自己进行锁定和解锁,而是为此使用 RAII 包装器,例如 std::lock_guard .这将锁定指定的互斥锁,直到锁定对象本身被销毁(通常是在它超出范围时)。

现在,虽然使用这些东西会极大地改进您的代码,但您实际的逻辑错误非常简单:您不应该与常量 3 进行比较,而应该与 playersLeft 进行比较。请注意,由于条件取决于此,因此您还必须在更改此变量时发出信号。

关于循环内的 C++ std::thread 同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10354472/

相关文章:

c++ - 大数组上的段错误

python - 为什么在 python 线程中监视键盘中断不起作用

ios - 总是预防性地将 UI 更改包装到主线程中?

c++ - 如何使用 std::shuffle 随机排列具有唯一指针的 vector ?

c++ - OpenCV:使用 StereoCamera 系统对颜色标记进行 3D 姿态估计

c++ - 堆栈的平衡表达

c++ - 通过接口(interface)完成 copy-and-swap

java - 使该类线程安全

c++ - Visual Studio 2010 支持哪些 C++11 功能?

c++ - 如果我们在不同的机器上将 c++11 mt19937 作为相同的种子,我们会得到相同的随机数序列吗