この簡略化されたコードで達成しようとしているのは次のとおりです。
- 2種類のプロセス(ルートと子、それぞれID/ランク=10と0-9)
- 初期化:
- ルートは「完了した」子をリッスンします
- すべてが完了すると、子供はルート通知を聞きます
- 勝者はいないが(まだすべてが完了しているわけではない):
- 子供は20%の確率で完了します(そしてルートに完了を通知します)
- ルートはすべてが完了したことを確認します
- すべて完了したら:「勝者」の子供に通知を送信します
私は次のようなコードを持っています:
int numprocs, id, arr[10], winner = -1;
bool stop = false;
MPI_Request reqs[10], winnerNotification;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
for (int half = 0; half < 1; half++) {
for (int round = 0; round < 1; round++) {
if (id == 10) { // root
// keeps track of who has "completed"
fill_n(arr, 10, -1);
for (int i = 0; i < 10; i++) {
MPI_Irecv(&arr[i], 1, MPI_INT, i, 0, MPI_COMM_WORLD, &reqs[i]);
}
} else if (id < 10) { // children
// listen to root of winner notification/indication to stop
MPI_Irecv(&winner, 1, MPI_INT, 10, 1, MPI_COMM_WORLD, &winnerNotification);
}
while (winner == -1) {
//cout << id << " is in loop" << endl;
if (id < 10 && !stop && ((rand() % 10) + 1) < 3) {
// children has 20% chance to stop (finish work)
MPI_Send(&id, 1, MPI_INT, 10, 0, MPI_COMM_WORLD);
cout << id << " sending to root" << endl;
stop = true;
} else if (id == 10) {
// root checks number of children completed
int numDone = 0;
for (int i = 0; i < 10; i++) {
if (arr[i] >= 0) {
//cout << "root knows that " << i << " has completed" << endl;
numDone++;
}
}
cout << "numDone = " << numDone << endl;
// if all done, send notification to players to stop
if (numDone == 10) {
winner = 1;
for (int i = 0; i < 10; i++) {
MPI_Send(&winner, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
}
cout << "root sent notification of winner" << endl;
}
}
}
}
}
MPI_Finalize();
デバッグからの出力はcout
次のようになります。問題は、rootがすべての子に完了の通知を受信していないことのようです。
2 sending to root
3 sending to root
0 sending to root
4 sending to root
1 sending to root
8 sending to root
9 sending to root
numDone = 1
numDone = 1
... // many numDone = 1, but why 1 only?
7 sending to root
...
おそらく配列に入れることができないと思いました:しかし、私は試しました
if (id == 1) {
int x = 60;
MPI_Send(&x, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
} else if (id == 0) {
MPI_Recv(&arr[1], 1, MPI_INT, 1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
cout << id << " recieved " << arr[1] << endl;
}
どちらが機能しますか。
アップデート
MPI_Barrier(MPI_COMM_WORLD)
whileループの終わりの前にaを追加すると、これは解決されたようですが、なぜですか?プロセスが同期しなくなったとしても、最終的には、子は完了したことをrootに送信し、rootはそれを「リッスン」して、それに応じて処理する必要がありますか?何が起こっているように見えますか?rootは実行を続け、子供が実行するためにすべてのリソースを占有しますか?またはここで何が起こっているのですか?
更新2:ルートから通知を受け取らない一部の子
さて、rootが@MichaelShの回答によって完了したという子供の通知を受け取らないという問題、私は親から受け取らない子供に焦点を合わせます。その問題を再現するコードは次のとおりです。
int numprocs, id, arr[10], winner = -1;
bool stop = false;
MPI_Request reqs[10], winnerNotification;
MPI_Init(NULL, NULL);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &id);
srand(time(NULL) + id);
if (id < 10) {
MPI_Irecv(&winner, 1, MPI_INT, 10, 0, MPI_COMM_WORLD, &winnerNotification);
}
MPI_Barrier(MPI_COMM_WORLD);
while (winner == -1) {
cout << id << " is in loop ..." << endl;
if (id == 10) {
if (((rand() % 10) + 1) < 2) {
winner = 2;
for (int i = 0; i < 10; i++) {
MPI_Send(&winner, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
}
cout << "winner notifications sent" << endl;
}
}
}
cout << id << " b4 MPI_Finalize. winner is " << winner << endl;
MPI_Finalize();
出力は次のようになります。
# 1 run
winner notifications sent
10 b4 MPI_Finalize. winner is 2
9 b4 MPI_Finalize. winner is 2
0 b4 MPI_Finalize. winner is 2
# another run
winner notifications sent
10 b4 MPI_Finalize. winner is 2
8 b4 MPI_Finalize. winner is 2
一部のプロセスが親からの通知を受け取らないように見えることに注意してください。なぜそれは、MPI_Wait
子プロセスがそれらをハングさせるだけなのか?では、どうすればこれを解決できますか?
また
あなたの場合はすべて
MPI_Barrier
そうです-それは子の応答が完了するのを待ちます。より良い解決策については私の答えを確認してください
これを行わない場合、各子の応答には数ミリ秒かかると思いますか?それで、私が待機/バリアをしなくても、送信後すぐに受信が発生することを期待しますか?プロセスがリソースを占有してしまい、他のプロセスが実行されない場合を除きますか?