我是MPI的新手并尝试在多个线程上并行化代码。我需要将大量数据传回主线程,并且无法清理MPI_Gather后得到的内存垃圾。以下是示例代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>
int main (int argc, char *argv[]) {
MPI_Init(&argc, &argv);
int rank, world_size;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
double *total=NULL;
double parcial[15000];
int W=world_size*15000;
if (rank == 0) {
total=malloc(sizeof(double) * world_size*15000);
}
else if (rank != 0) {
for(int i=0; i<15000; i++)parcial[i] = rank*i*0.1;
}
MPI_Barrier(MPI_COMM_WORLD);
if(rank==0) for(int ii=0; ii<W; ii++)total[ii]=0.;
MPI_Gather(parcial,15000,MPI_DOUBLE,total,15000,MPI_DOUBLE,0,MPI_COMM_WORLD);
if (rank == 0) {
int N=world_size*15000;
for(int i=0; i<N; i++) printf("%f ", total[i]);
}
free(total);
MPI_Finalize();
}
如果你运行带有多个线程的代码(我已经试过3,4,5 ...),它总是在接收缓冲区的开头有垃圾,即使我在调用MPI_Gather之前明确地将total [ii]置为零并设置障碍。是因为我实际上只有两个内核吗?但我已经读过,MPI无论如何都会创建一个虚拟机。有没有办法清理它并获得可靠的聚集?
增加:
我想,这个垃圾可能来自零线程。为什么它不会在第25行之后变为零?
答案 0 :(得分:3)
摘自MPI_Gather的MPI手册页:
每个进程(包括根进程)发送其内容 将缓冲区发送到根进程。
因此,recv缓冲区total
的前15000个元素将在根进程中包含parcial
的元素。这在您的代码中保留了一致性。
编辑:@Gilles评论说可以使用MPI_IN_PLACE
来避免在根进程上进行初始化。这是一个显示其效果的例子:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc, char *argv[])
{
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
int *in_place_total = calloc(sizeof(int), size);
int *total = calloc(sizeof(int), size);
int sendval = rank-5000;
MPI_Gather(&sendval, 1, MPI_INT,
total, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (rank == 0)
assert(total[0] == -5000);
if (rank)
MPI_Gather(&sendval, 1, MPI_INT,
in_place_total, 1, MPI_INT, 0, MPI_COMM_WORLD);
else
MPI_Gather(MPI_IN_PLACE, 1, MPI_INT,
in_place_total, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (rank == 0)
assert(in_place_total[0] == 0);
free(total);
free(in_place_total);
MPI_Finalize();
}