在 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) 您的计数不正确,因为它们必须反映数组xreal
和gene
中元素的实际数量(数据类型必须再次连续才能正确)。要回答您的实际问题:使用此数据类型的 MPI_Send
和 MPI_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_Send
和MPI_Recv
对。
扩展这些点:
-
在 C 中,当您有一个指向指针的指针(如
int **gene
)时,您最初为 nRow
指针分配内存,指向内存中每一行的整数。这个初始malloc
(gene[iRow]
,int *
变量)的元素在内存中都是连续的。请注意,这些元素最终实际指向的可能不是连续的;事实上,他们几乎可以肯定不是。然后,当您为每个行元素分配内存时(int *
,可由gene[iRow]
访问,您在内存中分配nCol
连续的整数。再次注意,虽然每一行都是连续的,但行iRow
和@987654337 @ 可能不会直接在彼此之后分配。在 C++ 中,new
和 new*
的工作方式完全相同。
为了解决这个问题,我建议你创建一个临时变量,比如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()
函数,如果它接受一个指针,则给它指向数组中第一个int
或double
的指针。如果它需要一个值,那么上面应该可以工作。
我无法正确获取偏移量 ()。我需要先为指针分配内存吗?以上是关于在 MPI 和 C 中,如何将结构信息的结构发送到从属进程并接收它们?的主要内容,如果未能解决你的问题,请参考以下文章
C ++ MPI创建并发送具有字段char [16]和整数的结构数组