2

std::thread を選択してスレッドの同時実行数を割り当てるという間違いを犯しました。他の方法を学ぶ時間は残っていません。ここで私を助けてくれることを願っています。私は、これらすべての種類のミューテックス、プロミス、フューチャーなどについて本当に混乱しています。多様なドキュメント/チュートリアルの欠如は気のめいるようです。したがって、3 つのスレッド (プレイヤー) に同じことをさせたい - グローバルな 2D 配列のインデックスとして 2 つの乱数を選択し、セルの値が 0 の場合はスレッドの Id に等しく設定し、それ以外の場合はスレッドの実行を停止する. スレッドが 1 つだけになるまで、これをループで実行します。私が必要としているのは、1 つのスレッドが 50 回目の繰り返しにならないように (次の前に) 3 つのスレッドを同期する方法を見つけることです。他のすべての人が反復を完了してから先に進みます。何らかの障壁が必要です。条件変数を使用してスレッドをスリープ状態にし、最後の終了スレッドがスレッドを起動するように通知するまでスレッドをスリープ状態にしようとしましたが、動作させることができませんでした。私の失敗した試みはコメントアウトされています:

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」内の式は、反復ごとに 1 つのスレッド (どちらか早い方) によって実行されると予想していましたが、奇妙な動作が発生するため、明らかにそうではありませんでした。どうやってするか?わかりました、コードは醜いかもしれませんし、すべてをクラスやメソッドなどの中に入れる必要がありますが、どんなに原始的であっても、これを機能させる必要があります。前もって感謝します!

4

1 に答える 1

1

andstd::atomic_int (std::atomic_boolまたはstd::atomic_flag. _ _

次に、ロックとロック解除を自分で行うのではなく、 のRAIIようにラッパーを使用しますstd::lock_guard。これにより、ロック オブジェクト自体が破棄されるまで (通常は範囲外になるまで)、指定されたミューテックスがロックされます。

これらを使用するとコードが大幅に改善されますが、実際の論理エラーは非常に単純です。定数 3 と比較するのではなく、 と比較する必要がありますplayersLeft。条件はこれに依存するため、この変数を変更するたびに通知する必要があることに注意してください。

于 2012-04-27T17:00:02.223 に答える