mpi_gather用于带动态数组的struct

时间:2012-12-07 10:20:34

标签: mpi

我有一个结构:

typedef struct 
{ 
double distance;
int* path;
} tour;

然后我尝试收集所有流程的结果:

   MPI_Gather(&best, sizeof(tour), MPI_BEST, all_best, sizeof(tour)*proc_count, MPI_BEST, 0, MPI_COMM_WORLD);

收集我的root后,看到all_best只包含1个普通元素,而其他元素则只有垃圾。 all_best的类型是tour *。

MPI_BEST的初始化:

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

block_lengths[0] = 1;
block_lengths[1] = city_count;

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

MPI_Address(&(tour->distance), &displacements[0]);
MPI_Address(&(tour->path), &displacements[1]);

displacements[1] = displacements[1] - displacements[0];
displacements[0] = 0;

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

欢迎任何想法。

1 个答案:

答案 0 :(得分:3)

除了将不正确的长度传递给MPI_Gather之外,MPI实际上并不遵循指针指针。使用这样的结构化类型,您将发送distance的值和path指针的值(本质上是一个在发送到其他进程时没有意义的地址)。如果假设distance基本上给出path中的元素数量,那么您可以通过MPI_GatherMPI_Gatherv的组合实现目标:

首先,收集长度:

int counts[proc_count];

MPI_Gather(&best->distance, 1, MPI_INT, counts, 1, MPI_INT, 0, MPI_COMM_WORLD);

现在counts填充了正确的长度,您可以继续使用MPI_Gatherv来接收所有路径:

int disps[proc_count];

disps[0] = 0;
for (int i = 1; i < proc_count; i++)
   disps[i] = disps[i-1] + counts[i-1];
// Allocate space for the concatenation of all paths
int *all_paths = malloc((disps[proc_count-1] + counts[proc_count-1])*sizeof(int));
MPI_Gatherv(best->path, best->distance, MPI_INT,
            all_paths, counts, disps, MPI_INT, 0, MPI_COMM_WORLD);

现在,您可以在all_paths中连接所有路径。您可以从counts[i]中的disps[i]位置开始all_paths元素来检查或提取单个路径。或者你甚至可以构建一个tour结构数组,并使它们使用已经分配和填充的路径存储:

tour *all_best = malloc(proc_count*sizeof(tour));
for (int i = 0; i < proc_count; i++)
{
   all_best[i].distance = counts[i];
   all_best[i].path = &all_paths[disps[i]];
}

或者您可以复制细分:

for (int i = 0; i < proc_count; i++)
{
   all_best[i].distance = counts[i];
   all_best[i].path = malloc(counts[i]*sizeof(int));
   memcpy(all_best[i].path, &all_paths[disps[i]], counts[i]*sizeof(int));
}
// all_paths is not needed any more and can be safely free()-ed

编辑:因为我忽略了tour结构的定义,所以上面的代码实际上适用于:

struct
{
   int distance;
   int *path;
}

其中distance包含path中重要元素的数量。这与您的情况不同,但如果没有关于tour.path如何分配(和大小)的一些信息,则很难给出具体的解决方案。