创建 MPI 结构时出现问题,调用 MPI_Bcast 时出现错误 11

Posted

技术标签:

【中文标题】创建 MPI 结构时出现问题,调用 MPI_Bcast 时出现错误 11【英文标题】:Problem creating an MPI struct, error 11 when calling MPI_Bcast 【发布时间】:2019-09-04 18:43:00 【问题描述】:

我想在进程之间传输一个结构,为此我正在尝试创建一个 MPI 结构。该代码用于蚁群优化 (ACO) 算法。

带有C结构的头文件包含:

    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/time.h>
    #include <math.h>
    #include <mpi.h>

    /* Constants */
    #define NUM_CITIES 100      // Number of cities
    //among others

    typedef struct 
        int city, next_city, tabu[NUM_CITIES], path[NUM_CITIES], path_index;
        double tour_distance;
     ACO_Ant;

我尝试按照this thread 中的建议构建我的代码。

程序代码:

    int main(int argc, char *argv[])
    
    MPI_Datatype MPI_TABU, MPI_PATH, MPI_ANT;

    // Initialize MPI
    MPI_Init(&argc, &argv);
    //Determines the size (&procs) of the group associated with a communicator (MPI_COMM_WORLD)
    MPI_Comm_size(MPI_COMM_WORLD, &procs);
    //Determines the rank (&rank) of the calling process in the communicator (MPI_COMM_WORLD)
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    MPI_Type_contiguous(NUM_CITIES, MPI_INT, &MPI_TABU);
    MPI_Type_contiguous(NUM_CITIES, MPI_INT, &MPI_PATH);
    MPI_Type_commit(&MPI_TABU);
    MPI_Type_commit(&MPI_PATH);

    // Create ant struct
    //int city, next_city, tabu[NUM_CITIES], path[NUM_CITIES], path_index;
    //double tour_distance;
    int blocklengths[6] = 1,1, NUM_CITIES, NUM_CITIES, 1, 1;
    MPI_Datatype    types[6] = MPI_INT, MPI_INT, MPI_TABU, MPI_PATH, MPI_INT, MPI_DOUBLE;
    MPI_Aint        offsets[6] =  offsetof( ACO_Ant, city ), offsetof( ACO_Ant, next_city), offsetof( ACO_Ant, tabu), offsetof( ACO_Ant, path ), offsetof( ACO_Ant, path_index ), offsetof( ACO_Ant, tour_distance );

    MPI_Datatype tmp_type;
    MPI_Aint lb, extent;

    MPI_Type_create_struct(6, blocklengths, offsets, types, &tmp_type);
    MPI_Type_get_extent( tmp_type, &lb, &extent );
    //Tried all of these
    MPI_Type_create_resized( tmp_type, lb, extent, &MPI_ANT );
    //MPI_Type_create_resized( tmp_type, 0, sizeof(MPI_ANT), &MPI_ANT );
    //MPI_Type_create_resized( tmp_type, 0, sizeof(ant), &MPI_ANT );
    MPI_Type_commit(&MPI_ANT);

    printf("Return: %d\n" , MPI_Bcast(ant, NUM_ANTS, MPI_ANT, 0, MPI_COMM_WORLD));
    

但是一旦程序到达 MPI_Bcast 命令,它就会崩溃并显示错误代码 11,我认为 MPI_ERR_TOPOLOGY as per this manual. 是一个段错误(信号 11)。

我也不确定一些代码为什么原程序的作者—— 有人能解释一下他们为什么创造吗

MPI_Aint displacements[3];
MPI_Datatype typelist[3];

大小为 3,当结构有 2 个变量时?

int block_lengths[2];

代码:

    void ACO_Build_best(ACO_Best_tour *tour, MPI_Datatype *mpi_type /*out*/)
    
        int block_lengths[2];
        MPI_Aint displacements[3];
        MPI_Datatype typelist[3];
        MPI_Aint start_address;
        MPI_Aint address;

        block_lengths[0] = 1;
        block_lengths[1] = NUM_CITIES;

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

        displacements[0] = 0;

        MPI_Address(&(tour->distance), &start_address);
        MPI_Address(tour->path, &address);
        displacements[1] = address - start_address;

        MPI_Type_struct(2, block_lengths, displacements, typelist, mpi_type);
        MPI_Type_commit(mpi_type);
    

我们将不胜感激。编辑:帮助解决问题,而不是微不足道的 *** 行话

【问题讨论】:

请附上Minimal, Complete, and Verifiable example。 已编辑。为完整性添加了更多代码。 blocklengthstypes 都不正确。 11 更可能与SIGSEGV 信号有关 你在这两种情况下都是正确的。请参阅Hristo Iliev's answer 了解更多信息。 【参考方案1】:

这部分错了:

int blocklengths[6] = 1,1, NUM_CITIES, NUM_CITIES, 1, 1;
MPI_Datatype    types[6] = MPI_INT, MPI_INT, MPI_TABU, MPI_PATH, MPI_INT, MPI_DOUBLE;
MPI_Aint        offsets[6] =  offsetof( ACO_Ant, city ), offsetof( ACO_Ant, next_city), offsetof( ACO_Ant, tabu), offsetof( ACO_Ant, path ), offsetof( ACO_Ant, path_index ), offsetof( ACO_Ant, tour_distance );

MPI_TABUMPI_PATH 数据类型已经涵盖了 NUM_CITIES 元素。当您将相应的块大小也指定为 NUM_CITIES 时,生成的数据类型将尝试访问 NUM_CITIES * NUM_CITIES 元素,可能会导致段错误(信号 11)。

要么将blocklengths 的所有元素设置为1,要么将types 数组中的MPI_TABUMPI_PATH 替换为MPI_INT

这部分也是错的:

MPI_Type_create_struct(6, blocklengths, offsets, types, &tmp_type);
MPI_Type_get_extent( tmp_type, &lb, &extent );
//Tried all of these
MPI_Type_create_resized( tmp_type, lb, extent, &MPI_ANT );
//MPI_Type_create_resized( tmp_type, 0, sizeof(MPI_ANT), &MPI_ANT );
//MPI_Type_create_resized( tmp_type, 0, sizeof(ant), &MPI_ANT );
MPI_Type_commit(&MPI_ANT);

MPI_Type_get_extent 返回的值调用MPI_Type_create_resized 是没有意义的,因为它只是复制了类型而没有实际调整它的大小。使用 sizeof(MPI_ANT) 是错误的,因为 MPI_ANT 不是 C 类型,而是 MPI 句柄,它是整数索引或指针(依赖于实现)。如果antACO_Ant 类型,它将与sizeof(ant) 一起使用,但是如果您调用MPI_Bcast(ant, NUM_ANTS, ...),那么ant 要么是一个指针,在这种情况下sizeof(ant) 只是指针大小,要么它是一个数组,在这种情况下,sizeof(ant)NUM_ANTS 的倍数。正确的调用是:

MPI_Type_create_resized(tmp_type, 0, sizeof(ACO_Ant), &ant_type);
MPI_Type_commit(&ant_type);

请不要在您自己的变量或函数名称中使用MPI_ 作为前缀。这使得代码不可读并且非常容易误导(“这是预定义的 MPI 数据类型还是用户定义的数据类型?”)

至于最后一个问题,作者可能有不同的结构。只要您使用正确数量的重要元素调用MPI_Type_create,没有什么能阻止您使用更大的数组。

注意:您不必提交从未在通信调用中直接使用的 MPI 数据类型。即,这两行是不必要的:

MPI_Type_commit(&MPI_TABU);
MPI_Type_commit(&MPI_PATH);

【讨论】:

感谢您的详细回答!我按照您的建议编辑了代码,它可以正常工作。请注意,我从原作者那里选择了 MPI_(name) 样式,因为我希望我的代码与他的代码兼容——我正在使用一些相同的函数等,而且因为这是我的第一个 MPI 项目。然而,正如你所说,我确实有时会感到困惑。是的,我没想到“MPI_Type_create_resized(tmp_type, 0, sizeof(MPI_ANT), &MPI_ANT);”工作,因为此时 mpi 类型为空,但我还是试了一下,因为我确定之前的代码是正确的(显然不是)。

以上是关于创建 MPI 结构时出现问题,调用 MPI_Bcast 时出现错误 11的主要内容,如果未能解决你的问题,请参考以下文章

使用 MPI_Bcast 时出现 MPI 分段错误

尝试排除进程级别0时出现MPI_Group_excl致命错误.c ++

C ++ MPI创建并发送具有字段char [16]和整数的结构数组

C++ MPI 创建并发送具有字段 char[16] 和 integer 的结构数组

Solidity:在映射中创建包含映射的结构时出现问题

创建VI将结构从DLL导入LabVIEW时出现问题