1

これは、私の以前の質問のフォローアップです。結論は、プログラムが間違っていたため、予期される動作が未定義であるというものでした。

ここで作成しようとしているのは、単純なエラー処理メカニズムです。そのために、空のメッセージに対する Irecv 要求を「アボート ハンドル」として使用し、それを通常のMPI_Wait呼び出しにアタッチ (および に変換MPI_WaitAny) して、プロセス 0 でエラーが発生し、プロセス 1 のブロックを解除できるようにしますMPI_Recv

何が起こっているかというと、内部メッセージ バッファリングが原因でMPI_Isend、他のプロセスが一致するMPI_Recv. ですので、キャンセルは仕方ありません。

すべてのプロセスが呼び出されMPI_Comm_freeたら、そのメッセージを完全に忘れることができることを望んでいましたが、結局のところ、そうではありません。MPI_Recv代わりに、次のコミュニケーターに配信されています。

だから私の質問は:

  1. これも間違ったプログラムですか、それとも MPI 実装 (Intel MPI 4.0.3) のバグですか?
  2. MPI_Isend呼び出しをに変更すると、プログラムは期待どおりに動作しますMPI_Issend。少なくともその場合、プログラムが正しいことを確認できますか?
  3. ここで車輪を再発明していますか?これを達成するためのより簡単な方法はありますか?

繰り返しになりますが、フィードバックは大歓迎です。


#include "stdio.h"
#include "unistd.h"
#include "mpi.h"
#include "time.h"
#include "stdlib.h"

int main(int argc, char* argv[]) {
    int rank, size;
    MPI_Group group;
    MPI_Comm my_comm;

    srand(time(NULL));
    MPI_Init(&argc, &argv);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_group(MPI_COMM_WORLD, &group);

    MPI_Comm_create(MPI_COMM_WORLD, group, &my_comm);
    if (rank == 0) printf("created communicator %d\n", my_comm);

    if (rank == 1) {
        MPI_Request req[2];
        int msg = 123, which;

        MPI_Isend(&msg, 1, MPI_INT, 0, 0, my_comm, &req[0]);
        MPI_Irecv(NULL, 0, MPI_INT, 0, 0, my_comm, &req[1]);

        MPI_Waitany(2, req, &which, MPI_STATUS_IGNORE);

        MPI_Barrier(my_comm);

        if (which == 0) {
            printf("rank 1: send succeed; cancelling abort handle\n");
            MPI_Cancel(&req[1]);
            MPI_Wait(&req[1], MPI_STATUS_IGNORE);
        } else {
            printf("rank 1: send aborted; cancelling send request\n");
            MPI_Cancel(&req[0]);
            MPI_Wait(&req[0], MPI_STATUS_IGNORE);
        }
    } else {
        MPI_Request req;
        int msg, r = rand() % 2;
        if (r) {
            printf("rank 0: receiving message\n");
            MPI_Recv(&msg, 1, MPI_INT, 1, 0, my_comm, MPI_STATUS_IGNORE);
        } else {
            printf("rank 0: sending abort message\n");
            MPI_Isend(NULL, 0, MPI_INT, 1, 0, my_comm, &req);
        }

        MPI_Barrier(my_comm);

        if (!r) {
            MPI_Cancel(&req);
            MPI_Wait(&req, MPI_STATUS_IGNORE);
        }
    }

    if (rank == 0) printf("freeing communicator %d\n", my_comm);
    MPI_Comm_free(&my_comm);

    sleep(2);

    MPI_Comm_create(MPI_COMM_WORLD, group, &my_comm);
    if (rank == 0) printf("created communicator %d\n", my_comm);

    if (rank == 0) {
        MPI_Request req;
        MPI_Status status;
        int msg, cancelled;

        MPI_Irecv(&msg, 1, MPI_INT, 1, 0, my_comm, &req);
        sleep(1);

        MPI_Cancel(&req);
        MPI_Wait(&req, &status);
        MPI_Test_cancelled(&status, &cancelled);

        if (cancelled) {
            printf("rank 0: receive cancelled\n");
        } else {
            printf("rank 0: OLD MESSAGE RECEIVED!!!\n");
        }
    }

    if (rank == 0) printf("freeing communicator %d\n", my_comm);
    MPI_Comm_free(&my_comm);

    MPI_Finalize();
    return 0;
}

出力:

created communicator -2080374784
rank 0: sending abort message
rank 1: send succeed; cancelling abort handle
freeing communicator -2080374784
created communicator -2080374784
rank 0: STRAY MESSAGE RECEIVED!!!
freeing communicator -2080374784
4

2 に答える 2

2

@kraffenetti による上記のコメントの 1 つで述べたように、送信されたメッセージが受信によって照合されないため、これは誤ったプログラムです。メッセージがキャンセルされたとしても、リモート側で一致する受信が必要です。これは、キャンセルが完了する前にメッセージが既に送信されているという事実のために、送信されたメッセージのキャンセルが成功しない可能性があるためです (つまり、ここの場合)。

この質問は、MPICH のチケットでこれに関するスレッドを開始しました。詳細については、こちらを参照してください。

于 2014-05-28T18:49:49.047 に答える