C 如何使用MPI传输带有动态数组的自定义结构?;

C 如何使用MPI传输带有动态数组的自定义结构?;,c,arrays,struct,mpi,C,Arrays,Struct,Mpi,有一个简单的例子来描述我的问题。 我有一个包含动态数组的自定义结构 struct my_data_type { int c; int d[]; }; 根进程(进程0)有一个这样的结构数组nums[4] 我想通过MPI\u Scatter将数组块发送到不同的进程(例如,2个进程)。这里的主要问题是我希望这个数组d[]是动态的 主要代码如下: int main(int argc, char* argv[]) { MPI_Init(NULL, NULL); int

有一个简单的例子来描述我的问题。 我有一个包含动态数组的自定义结构

struct my_data_type {
    int c;
    int d[];
};
根进程(进程0)有一个这样的结构数组
nums[4]

我想通过
MPI\u Scatter
将数组块发送到不同的进程(例如,2个进程)。这里的主要问题是我希望这个数组
d[]
是动态的

主要代码如下:

int main(int argc, char* argv[]) {

    MPI_Init(NULL, NULL);

    int my_size; MPI_Comm_size(MPI_COMM_WORLD, &my_size);
    int my_rank; MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    int len = 2; //example: the dynamic array d contains len=2 elements
    my_data_type *nums //nums[4]
        = (my_data_type*)malloc((sizeof(my_data_type) + sizeof(int) * len) * 4);
    my_data_type *sub_nums //sub_nums[2]
        = (my_data_type*)malloc((sizeof(my_data_type) + sizeof(int) * len) * 2);

    if (my_rank == 0) { //just some examples
        nums[0].c = 0; nums[1].c = 1; nums[2].c = 2; nums[3].c = 3;
        nums[0].d[0] = 10; nums[1].d[0] = 11; nums[2].d[0] = 12; nums[3].d[0] = 13;
        nums[0].d[1] = 14; nums[1].d[1] = 15; nums[2].d[1] = 16; nums[3].d[1] = 17;
    }

    MPI_Datatype mpi_data_type; //new datatype
    int blocklens[2];
    MPI_Datatype old_types[2];
    MPI_Aint indices[2];

    blocklens[0] = 1; blocklens[1] = len;
    old_types[0] = MPI_INT; old_types[1] = MPI_INT;
    MPI_Address(&nums[0].c, &indices[0]);
    MPI_Address(&nums[0].d[0], &indices[1]);
    indices[1] = indices[1] - indices[0];
    indices[0] = 0;

    MPI_Type_create_struct(2, blocklens, indices, old_types, &mpi_data_type);
    MPI_Type_commit(&mpi_data_type);

    MPI_Scatter(nums, 2, mpi_data_type,
                sub_nums, 2, mpi_data_type,
                0, MPI_COMM_WORLD);

    cout << "rank " << my_rank << ": " << endl;
    cout << "c: " << sub_nums[0].c << ", " << sub_nums[1].c << endl;
    cout << "d: " << sub_nums[0].d[0] << ", " << sub_nums[0].d[1] << ", ";
    cout << sub_nums[1].d[0] << ", " << sub_nums[1].d[1] << endl;

    MPI_Finalize();

    return 0;
}
rank 0: 
c: 0, 10
d: 10, 14, 14, 15
rank 1: 
c: 33, 0
d: 0, 0, 0, 1
但如果不是,结果如下:

int main(int argc, char* argv[]) {

    MPI_Init(NULL, NULL);

    int my_size; MPI_Comm_size(MPI_COMM_WORLD, &my_size);
    int my_rank; MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

    int len = 2; //example: the dynamic array d contains len=2 elements
    my_data_type *nums //nums[4]
        = (my_data_type*)malloc((sizeof(my_data_type) + sizeof(int) * len) * 4);
    my_data_type *sub_nums //sub_nums[2]
        = (my_data_type*)malloc((sizeof(my_data_type) + sizeof(int) * len) * 2);

    if (my_rank == 0) { //just some examples
        nums[0].c = 0; nums[1].c = 1; nums[2].c = 2; nums[3].c = 3;
        nums[0].d[0] = 10; nums[1].d[0] = 11; nums[2].d[0] = 12; nums[3].d[0] = 13;
        nums[0].d[1] = 14; nums[1].d[1] = 15; nums[2].d[1] = 16; nums[3].d[1] = 17;
    }

    MPI_Datatype mpi_data_type; //new datatype
    int blocklens[2];
    MPI_Datatype old_types[2];
    MPI_Aint indices[2];

    blocklens[0] = 1; blocklens[1] = len;
    old_types[0] = MPI_INT; old_types[1] = MPI_INT;
    MPI_Address(&nums[0].c, &indices[0]);
    MPI_Address(&nums[0].d[0], &indices[1]);
    indices[1] = indices[1] - indices[0];
    indices[0] = 0;

    MPI_Type_create_struct(2, blocklens, indices, old_types, &mpi_data_type);
    MPI_Type_commit(&mpi_data_type);

    MPI_Scatter(nums, 2, mpi_data_type,
                sub_nums, 2, mpi_data_type,
                0, MPI_COMM_WORLD);

    cout << "rank " << my_rank << ": " << endl;
    cout << "c: " << sub_nums[0].c << ", " << sub_nums[1].c << endl;
    cout << "d: " << sub_nums[0].d[0] << ", " << sub_nums[0].d[1] << ", ";
    cout << sub_nums[1].d[0] << ", " << sub_nums[1].d[1] << endl;

    MPI_Finalize();

    return 0;
}
rank 0: 
c: 0, 10
d: 10, 14, 14, 15
rank 1: 
c: 33, 0
d: 0, 0, 0, 1

如您所见,我知道问题在于动态数组,但我不能在项目中使用静态数组。那么我如何更改上面的代码以获得预期的结果呢?

我可能在这一点上错了,但我认为您想要保存一个指向数组的指针(即
int**myArrPointer
),因为我认为您需要做的是,因为我不认为您可以在C中分配数组(即
myArr=myOtherArr
):

  • 计算新数组的大小
  • 为新阵列分配内存
  • 在结构中存储指向该新数组的指针
  • 您的结构最终可能需要如下所示:

    struct my_data_type 
    {
        int ArrSize;
        int** PointerToAnArray;
    };
    
    void SomeFunForSwappingArrays(my_data_type* instance, int newArrSize)
    {
        int* newArr = (int*)malloc(newArrSize*sizeof(int));
        //free the memory of the old array. if you don't need the data anymore, i would
        //consider doing this.
        free(*(instance->PointerToAnArray));
        //save the memory address of the new array
        instance->PointerToAnArray = &newArr;
        instance->ArrSize = newArrSize;
    }
    

    希望能有所帮助。

    您的根本问题不是mpi,而是使用具有灵活数组成员的struct数组。下面是一个示例程序来说明这个问题

    #包括
    #包括
    #包括
    类型定义结构;
    结构
    {
    INTC;
    int d[];
    };
    int main(int argc,char*argv[])
    {
    断言(sizeof(s)=sizeof(int));
    int len=4;
    s*okay=malloc(sizeof(*okay)+sizeof(int)*len);
    intptr\u t true\u size=(intptr\u t)&ok->d[len](intptr\u t)(ok);
    断言(true_size==((len+1)*sizeof(int));
    int-nbad=6;
    s*bad=malloc((sizeof(*bad)+sizeof(int)*len)*nbad);
    intptr\u t坏大小=(intptr\u t)和坏[1]-(intptr\u t)和坏[0];
    /*这种大小不匹配意味着's'的数组不会执行您认为它们会执行的操作*/
    断言(错误大小!=真实大小);
    断言(bad_size==sizeof(int));
    断言((字符*)&bad[1]==(字符*)&bad[0].d[0]);
    断言((字符*)&bad[2]==(字符*)&bad[0].d[1]);
    断言((字符*)&bad[3]==(字符*)&bad[0].d[2]);
    断言((字符*)&bad[1].d[0]==(字符*)&bad[0].d[1]);
    断言((字符*)&bad[2].d[0]==(字符*)&bad[0].d[2]);
    断言((字符*)&bad[3].d[0]==(字符*)&bad[0].d[3]);
    }
    
    要处理具有灵活数组成员的结构数组,您需要手动计算用于索引的内存偏移量,而不是依赖编译器。因此,您可以定义这样的帮助器函数:

    struct my_data_type 
    {
        int ArrSize;
        int** PointerToAnArray;
    };
    
    void SomeFunForSwappingArrays(my_data_type* instance, int newArrSize)
    {
        int* newArr = (int*)malloc(newArrSize*sizeof(int));
        //free the memory of the old array. if you don't need the data anymore, i would
        //consider doing this.
        free(*(instance->PointerToAnArray));
        //save the memory address of the new array
        instance->PointerToAnArray = &newArr;
        instance->ArrSize = newArrSize;
    }
    
    s*s_索引(常数s*a,整数len,整数索引)
    {
    uintptpr_t true_size=sizeof(*a)+len*sizeof(int);
    返回(s*)((char*)a+索引*真实大小);
    }
    
    然后使用
    s_index
    访问所需的数组成员,而不是
    bad[0]
    bad[1]
    构造:

    s*first=s_索引(坏,len,0);
    s*second=s_指数(坏,len,1);
    断言((字符*)&first->d[len]==(字符*)second;
    
    如果您使用
    d[]
    sizeof(…)
    不是您所期望的,因此会出现短时间的malloc和数据损坏。亲爱的朋友,感谢您的评论。我发现了一个bug,并对其进行了更新(结构数组的malloc
    nums[4]
    sub\u nums[4]
    )。但这仍然是错误的。而且我不能malloc动态数组
    d[]
    ,因为数组类型“int[]”是不可赋值的。我认为你不能用一种合理的方式使用灵活的数组成员进行结构数组。我同意你的看法。所以实际上我想知道如何用另一种方式处理具有灵活数组成员的结构数组。我更新了我的答案,介绍了如何用FAMs处理结构数组。谢谢你的建议。但问题是向其他MPI节点发送指针(而不是数组)似乎没有意义。请检查这个问题,了解通过MPI通过指针发送数据的情况。看起来你真的可以。直到现在我还没有听说过MPI,所以我很好奇这是否可能。另外,数组在C中用作函数输入时会衰减为指针,所以对我来说,将数组放入函数中会起作用是没有意义的,而将指针放入函数中则不会。我认为由于衰变的原因,函数将使用指针。我发现指针实际上可以工作,但当我在自定义结构中使用指针时,出现了一些问题。事实上,我的观点就像Jeff的评论一样,他说:“你不能发送指针,因为它在分配它的进程之外是没有意义的。”一个进程的内存地址对其他进程(在其他计算机中)没有用处。无论如何,我将试着单独使用指针,而不是在结构中。那可能有用。谢谢你的帮助!!你是对的,我可以根据自己的问题来调整。