3

動的に割り当てられた配列を含むカスタムMPIデータ型を使用するとすぐに、MPI_Reduce()がセグメンテーション違反を起こす理由がわかりません。誰か知っている ?次のコードは、MPI_Reduce()内の2つのプロセッサでクラッシュします。ただし、メンバーdouble * d int MyTypeを削除し、それに応じて演算子とMPIタイプのルーチンを変更すると、問題なく削減が行われます。

動的に割り当てられた配列の使用に問題がありますか、それとも私が行うことに根本的に問題がありますか?

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>



typedef struct mytype_s
{
    int c[2];
    double a;
    double b;
    double *d;
} MyType;



void CreateMyTypeMPI(MyType *mt, MPI_Datatype *MyTypeMPI)
{
    int block_lengths[4];                        // # of elt. in each block
    MPI_Aint displacements[4];                   // displac.
    MPI_Datatype typelist[4];                    // list of types
    MPI_Aint start_address, address;            // use for calculating displac.
    MPI_Datatype myType;

    block_lengths[0] = 2;
    block_lengths[1] = 1;
    block_lengths[2] = 1;
    block_lengths[3] = 10;

    typelist[0] = MPI_INT;
    typelist[1] = MPI_DOUBLE;
    typelist[2] = MPI_DOUBLE;
    typelist[3] = MPI_DOUBLE;

    displacements[0] = 0;

    MPI_Address(&mt->c, &start_address);
    MPI_Address(&mt->a, &address);
    displacements[1] = address - start_address;

    MPI_Address(&mt->b,&address);
    displacements[2] = address-start_address;

    MPI_Address(&mt->d, &address);
    displacements[3] = address-start_address;

    MPI_Type_struct(4,block_lengths, displacements,typelist,MyTypeMPI);
    MPI_Type_commit(MyTypeMPI);
}




void MyTypeOp(MyType *in, MyType *out, int *len, MPI_Datatype *typeptr)
{
    int i;
    int j;

    for (i=0; i < *len; i++)
    {
        out[i].a += in[i].a;
        out[i].b += in[i].b;
        out[i].c[0] += in[i].c[0];
        out[i].c[1] += in[i].c[1];

        for (j=0; j<10; j++)
        {
            out[i].d[j] += in[i].d[j];
        }
    }
}




int main(int argc, char **argv)
{
    MyType mt;
    MyType mt2;
    MPI_Datatype MyTypeMPI;
    MPI_Op MyOp;
    int rank;
    int i;

    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&rank);


    mt.a = 2;
    mt.b = 4;
    mt.c[0] = 6;
    mt.c[1] = 8;
    mt.d = calloc(10,sizeof *mt.d);
    for (i=0; i<10; i++) mt.d[i] = 2.1;

    mt2.a = 0;
    mt2.b = 0;
    mt2.c[0] = mt2.c[1] = 0;
    mt2.d = calloc(10,sizeof *mt2.d);


    CreateMyTypeMPI(&mt, &MyTypeMPI);
    MPI_Op_create((MPI_User_function *) MyTypeOp,1,&MyOp);

    if(rank==0) printf("type and operator are created now\n");

    MPI_Reduce(&mt,&mt2,1,MyTypeMPI,MyOp,0,MPI_COMM_WORLD);

    if(rank==0)
    {




        for (i=0; i<10; i++) printf("%f ",mt2.d[i]);
        printf("\n");
    }

    free(mt.d);
    free(mt2.d);
    MPI_Finalize();

    return 0;
}
4

1 に答える 1

2

あなたの構造体を見てみましょう:

typedef struct mytype_s
{
    int c[2];
    double a;
    double b;
    double *d;
} MyType;

...

MyType mt;
mt.d = calloc(10,sizeof *mt.d);

そして、MPIタイプとしてのこの構造体の説明:

displacements[0] = 0;

MPI_Address(&mt->c, &start_address);
MPI_Address(&mt->a, &address);
displacements[1] = address - start_address;

MPI_Address(&mt->b,&address);
displacements[2] = address-start_address;

MPI_Address(&mt->d, &address);
displacements[3] = address-start_address;

MPI_Type_struct(4,block_lengths, displacements,typelist,MyTypeMPI);

問題は、このMPI構造体は、ここでの定義で使用した構造体の1つのインスタンスにのみ適用されることですcalloc()どこからメモリを取得するかを決定する場所をすべて制御することはできません。仮想メモリのどこにあってもかまいません。作成してインスタンス化するこれらのタイプの次の1つでは、d配列の変位は完全に異なります。realloc()また、同じ構造体を使用している場合でも、現在の配列のサイズを変更すると、mt変位が異なる可能性があります。

したがって、これらのタイプのいずれかを使用して送信、受信、削減などを行うと、MPIライブラリはおそらく無意味な置き換えに忠実に移動し、そこから読み取りまたは書き込みを試みます。これにより、セグメンテーション違反が発生する可能性があります。

これはMPIのことではないことに注意してください。低レベルの通信ライブラリを使用する場合、またはディスクからの書き込み/読み取りを試みる場合にも、同じ問題が発生します。

オプションには、他のフィールドがある場合とない場合のいずれかで、配列をメッセージに手動で「マーシャリング」することが含まれます。または、定義された最大サイズの配列としてdを定義するなどして、dが配置されている場所に予測可能性を追加します。

于 2012-11-17T23:48:15.913 に答える