6

誰かが私のためにMPI_Waitall関数に光を当てることができるのだろうか。MPI_IsendとMPI_Irecvを使用して情報を渡すプログラムがあります。すべての送受信が完了すると、プログラム内の1つのプロセス(この場合はプロセス0)がメッセージを出力します。Isend / Irecvは機能していますが、プログラムのランダムなポイントでメッセージが出力されます。そのため、MPI_Waitallを使用して、メッセージを出力する前にすべての要求が完了するまで待機しようとしています。次のエラーメッセージが表示されます。

Fatal error in PMPI_Waitall: Invalid MPI_Request, error stack:
PMPI_Waitall(311): MPI_Waitall(count=16, req_array=0x16f70d0, status_array=0x16f7260) failed
PMPI_Waitall(288): The supplied request in array element 1 was invalid (kind=0)

関連するコードは次のとおりです。

MPI_Status *status;
MPI_Request *request;

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
status = (MPI_Status *) malloc(numtasks * sizeof(MPI_Status));
request = (MPI_Request *) malloc(numtasks * sizeof(MPI_Request));

/* Generate Data to send */
//Isend/Irecvs look like this:
MPI_Isend(&data, count, MPI_INT, dest, tag, MPI_COMM_WORLD, &request[taskid]);
MPI_Irecv(&data, count, MPI_INT, source, tag, MPI_COMM_WORLD, &request[taskid]);
MPI_Wait(&request[taskid], &status[taskid]

/* Calculations and such */

if (taskid == 0) {
        MPI_Waitall (numtasks, request, status);
        printf ("All done!\n");
}
MPI_Finalize();

MPI_Waitallを呼び出さないと、プログラムは正常に実行されますが、すべてのIsend / Irecvが完了した後ではなく、プロセス0のIsend/Irecvメッセージが完了するとすぐに「Alldone」メッセージが出力されます。

あなたが提供できるどんな助けにも感謝します。

4

1 に答える 1

11

requestつまり、配列の1つの要素のみを設定しますrequest[taskid](つまり、送信要求ハンドルを受信ハンドルで上書きすると、前者は取り返しのつかないほど失われます)。MPIは分散メモリマシンのプログラムに使用され、各MPIプロセスには独自のrequestアレイのコピーがあることを忘れないでください。ランクに1つの要素を設定taskidしても、値が他のランクに魔法のように伝播されることはありません。伝播されたとしても、リクエストにはローカルの有効性しかありません。適切な実装は次のとおりです。

MPI_Status status[2];
MPI_Request request[2];

MPI_Init(&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &taskid);
MPI_Comm_size (MPI_COMM_WORLD, &numtasks);

/* Generate Data to send */
//Isend/Irecvs look like this:
MPI_Isend (&data, count, MPI_INT, dest, tag, MPI_COMM_WORLD, &request[0]);
//          ^^^^
//           ||
//      data race !!
//           ||
//          vvvv
MPI_Irecv (&data, count, MPI_INT, source, tag, MPI_COMM_WORLD, &request[1]);
// Wait for both operations to complete
MPI_Waitall(2, request, status);

/* Calculations and such */

// Wait for all processes to reach this line in the code
MPI_Barrier(MPI_COMM_WORLD);

if (taskid == 0) {
  printf ("All done!\n");
}
MPI_Finalize();

ちなみに、コードにはデータ競合があります。MPI_Isendとは両方ともMPI_Irecv同じデータバッファを使用していますが、これは正しくありません。dataのコンテンツを送信destしてから受信しようとしている場合は、代わりにsourceを使用MPI_Sendrecv_replaceして、非ブロッキング操作を忘れてください。

MPI_Status status;

MPI_Init(&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &taskid);
MPI_Comm_size (MPI_COMM_WORLD, &numtasks);

/* Generate Data to send */
MPI_Sendrecv_replace (&data, count, MPI_INT, dest, tag, source, tag,
                      MPI_COMM_WORLD, &status);

/* Calculations and such */

// Wait for all processes to reach this line in the code
MPI_Barrier(MPI_COMM_WORLD);

if (taskid == 0) {
  printf ("All done!\n");
}
MPI_Finalize();
于 2013-03-15T20:38:31.717 に答える