在 MPI 和 C 中,如何将结构信息的结构发送到从属进程并接收它们?

Posted

技术标签:

【中文标题】在 MPI 和 C 中,如何将结构信息的结构发送到从属进程并接收它们?【英文标题】:in MPI and C, how to send the the struct of struct information to slave processes and receive them? 【发布时间】:2015-11-17 15:17:32 【问题描述】:

如代码所示,我在 c 中有两个结构。经过一些输入读取和initialize_pop(parent_pop),生成了包含4个个体的parent_pop。然后我必须将每个个体发送到每个进程(4个进程)以评估并在每个进程上生成新的个体(总共还是4个个体),然后接收这 4 个新个体在主进程中形成一个名为 child_pop 的新群体。这是我的伪程序。感谢任何帮助。提前致谢。

typedef struct
double *xreal;
int **gene;
double crowd_dist;

individual;

typedef struct

individual *ind;

population;



Here is the main program:
int main (int argc, char **argv)

population *parent_pop;
int i, my_id, num_procs;
MPI_Init(&argc, &argv);
// Find out process ID and process number //
MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
input_read();/*read input*/
initialize_pop (parent_pop);/*generate 4 individuals to form the parent_pop*/
MPI_Datatype MPI_individual;
int count = 3;
int blocklens[] =  1, 1, 1 ;
MPI_Aint disps[3];
MPI_Datatype old_types[] =  MPI_int, MPI_double, MPI_double ;
disps[0] = offsetof(individual, *xreal);
disps[1] = offsetof(individual, **gene);
disps[2] = offsetof(individual, crowd_dist);
MPI_Type_struct(count, blocklens, disps, old_types, &MPI_individual);
MPI_Type_commit(&MPI_individual);

*********Part need help****************************
send each individual to each process;
*********Part need help****************************

evaluate(parent_pop);/*evaluate each individual in each process*/
genearte_new_pop(child_pop);/*generate 4 new individuals to form the child_pop*/

*********Part need help****************************
receive each individual information from the slave processes to get the child_pop in the master process
*********Part need help****************************


【问题讨论】:

我看到了一些错误:(1) 发送int **gene 并不简单,因为在分配此内存时,它不会是连续的——只有每一行在内存中是连续的。 (2) 您的类型与您的 individual 结构本身不匹配。应该是MPI_double, MPI_int, MPI_double。 (3) 您的计数不正确,因为它们必须反映数组xrealgene 中元素的实际数量(数据类型必须再次连续才能正确)。要回答您的实际问题:使用此数据类型的 MPI_SendMPI_Recv 应该可以工作。 非常感谢。我是一个编程初学者。如果可能,请您详细说明这些(1)由于该程序中的其他功能,我必须使用**gene,那么我应该如何发送**gene? (2)计数不是派生类型的元素块数吗?它应该等于blocklens数组的大小吗? (3) 再次感谢您的回答! (1) 当你第一次分配你的gene 数组时,你必须将它分配在连续的内存中(通常通过制作一维数组来完成)。如果您真的想保持程序的其余部分相同,那么最初将geneTemp 分配为一维数组,并将二维数组gene 的每个指针设置为对应于一维数组geneTemp 的内存位置。不漂亮,但这意味着您不必更改程序的任何其他部分。 (2) 是的,通过 MPI 发送的计数应该是数组的大小。 谢谢!如果可能的话,请告诉我分配geneTemp和gene的基本代码。另外,*xreal怎么样,如何将这个指针指向的数组传递给其他进程? 【参考方案1】:

此时,我决定正式回答您的问题,因为 cmets 中发生的事情太多,其他人无法跟进。

我看到你需要做的三件主要事情是(可能还有更多):

    在内存中连续分配int **gene,以便能够通过MPI一次性发送。 确保您为oldtypes 声明的类型与您的individual 结构的类型顺序相匹配。 确保您的计数正确地反映了数组中元素的实际数量(可能所有这些元素都应该是连续的,以使您尽可能轻松地完成此操作)。

正确设置MPI_individual 后,您应该能够使用MPI_individual 作为类型发送一个简单的MPI_SendMPI_Recv 对。

扩展这些点:

    在 C 中,当您有一个指向指针的指针(如 int **gene)时,您最初为 nRow 指针分配内存,指向内存中每一行的整数。这个初始mallocgene[iRow]int * 变量)的元素在内存中都是连续的。请注意,这些元素最终实际指向的可能不是连续的;事实上,他们几乎可以肯定不是。然后,当您为每个行元素分配内存时(int *,可由gene[iRow] 访问,您在内存中分配nCol 连续的整数。再次注意,虽然每一行都是连续的,但行iRow 和@987654337 @ 可能不会直接在彼此之后分配。在 C++ 中,newnew* 的工作方式完全相同。

为了解决这个问题,我建议你创建一个临时变量,比如geneTemp,这将是你分配内存的方式。

int *geneTemp;
geneTemp = (int *)malloc(nRow*nCol*sizeof(int));

现在您有一个连续的内存块(nRow*nCol 整数),您可以将原始的 int **gene 指向该内存块中的正确位置,使用类似的方法:

int **gene;
for (int iRow = 0; iRow < nRow; ++iRow) 
    gene[iRow] = &geneTemp[iRow*nCol + 0];

我承认这并不漂亮,但这种设置允许您重新使用所有旧代码,但现在二维数组 gene 指向一个连续的整数块。

    这是一个简单的解决方法。它应该是:

    MPI_Datatype old_types[] = MPI_double, MPI_int, MPI_double;
    

    匹配您的 individual 结构。

    现在,当您设置 MPI_individual 类型时,您必须实际发送每个数组中的值。发送指针是没有意义的,因为每个 MPI 进程都有不同的内存空间。进程 0 中地址 55 中的内容与进程 1 中地址 55 中的内容完全不同。

发送实际数据,而不是指针:

int blocklens[3] =  nReals, nRows*nCols, 1 ;
MPI_Aint disps[3];
disps[0] = offsetof(individual, xreal[0]);
disps[1] = offsetof(individual, gene[0][0]);
disps[2] = offsetof(individual, crowd_dist);

(至少是这样的......我不知道offsetof()是什么,但这是我认为应该在这里使用的方式。我没有测试过这段代码。)

我希望这更清楚地解释了内存是如何设置的,特别是应该如何设置 MPI 派生数据类型。

【讨论】:

感谢您的好意。还有一个小问题是,由于现在单个结构中的每个大小都不同(gene 是 nrow*ncol,xreal 是 nreal),我应该如何确定 MPI_Type_struct 中的计数?再次感谢! n 另外,我测试过代码,offsetof是找地址的。似乎 offsetof(individual, xreal[0]) 会导致错误。寻找解决方案。 你是说每个结构都有不同的nrow/ncol?那么是的,你会遇到一个问题:你不能创建一个不断改变大小的 MPI 数据类型。我认为不幸的是,每次您想通过发送第一个数组,然后是第二个,然后是 int 并在另一侧重建结构来发送结构时,您都必须简单地照看它... 对于offset()函数,如果它接受一个指针,则给它指向数组中第一个intdouble的指针。如果它需要一个值,那么上面应该可以工作。 我无法正确获取偏移量 ()。我需要先为指针分配内存吗?

以上是关于在 MPI 和 C 中,如何将结构信息的结构发送到从属进程并接收它们?的主要内容,如果未能解决你的问题,请参考以下文章

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

MPI在C ++中发送具有向量属性的结构

C-MPI 发送创建的带有字符数组的 typedef 结构

MPI - 在使用 MPI_Probe() 时发送我自己的结构

MPI 发送带有字节数组和整数的结构

使用 MPI_Type_create_struct() 在 C 中传输包含动态数组的结构