c++ - MPI 中的动态内存分配

标签 c++ c mpi dynamic-memory-allocation openmpi

我是 MPI 的新手。我写了一个简单的代码来使用多进程显示矩阵。假设我有一个 8x8 矩阵并启动具有 4 个进程的 MPI 程序,第 2 行将打印我的第 1 个进程,第 2 组 2 行将由第 2 个线程打印,依此类推。

#define S 8

MPI_Status status;

int main(int argc, char *argv[])
{
int numtasks, taskid;
int i, j, k = 0;

MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

int rows, offset, remainPart, orginalRows, height, width;
int **a;
//  int a[S][S];

if(taskid == 0)
{
    cout<<taskid<<endl;
    height = width = S;

    a = (int **)malloc(height*sizeof(int *));
    for(i=0; i<height; i++)
        a[i] =  (int *)malloc(width*sizeof(int));

    for(i=0; i<S; i++)
        for(j=0; j<S; j++)
            a[i][j] = ++k;

    rows = S/numtasks;
    offset = rows;
    remainPart = S%numtasks;

    cout<<"Num Rows : "<<rows<<endl;

    for(i=1; i<numtasks; i++)
        if(remainPart > 0)
        {
            orginalRows = rows;
            rows++;
            remainPart--;

            MPI_Send(&offset, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
            MPI_Send(&rows, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
            MPI_Send(&width, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
            MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD);

            offset += rows;
            rows = orginalRows;
        }
        else
        {
            MPI_Send(&offset, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
            MPI_Send(&rows, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
            MPI_Send(&width, 1, MPI_INT, i, 1, MPI_COMM_WORLD);
            MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD);

            offset += rows;
        }

        //Processing
        rows = S/numtasks;
        for(i=0; i<rows; i++)
        {
            for(j=0; j<width; j++)
                cout<<a[i][j]<<"\t";
            cout<<endl;
        }
}else
{
    cout<<taskid<<endl;

    MPI_Recv(&offset, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
    MPI_Recv(&rows, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
    MPI_Recv(&width, 1, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
    a = (int **)malloc(rows*sizeof(int *));
    for(i=0; i<rows; i++)
        a[i] =  (int *)malloc(width*sizeof(int));
    MPI_Recv(&a, rows*width, MPI_INT, 0, 1, MPI_COMM_WORLD, &status);
    cout<<"Offset : "<<offset<<"\nRows : "<<rows<<"\nWidth : "<<width<<endl;

    for(i=0; i<rows; i++)
    {
        for(j=0; j<width; j++)
            cout<<a[i][j]<<"\t";
        cout<<endl;
    }
}

getch();
MPI_Finalize();

return 0;
}

这是我的完整代码,这里我为 'a' 动态分配了内存,同时打印 a[i][j],在 else 部分下,出现运行时错误。如果我将动态内存分配更改为静态,例如将 int **a 更改为 int a[N][N] 并删除

    a = (int **)malloc(rows*sizeof(int));
    for(i=0; i<rows; i++)
        a[i] =  (int *)malloc(width*sizeof(int));

它完美地工作。

最佳答案

至少有两种动态分配二维数组的方法。

第一个是@HRoid 中的一个:每行一次分配一个。看here获得方案。

第二个是@Claris 推荐的,它将确保数据在内存中是连续的。这是许多 MPI 操作所必需的……FFTW(二维快速傅立叶变换)或 Lapack(线性代数的密集矩阵)等库也需要它。您的程序可能会在

MPI_Send(&a[offset][0], rows*S, MPI_INT,i,1, MPI_COMM_WORLD);

如果 S>1,此程序将尝试发送行尾 n°offset 之后的项目...这可能会触发段错误或未定义的行为。

你可以分配你的数组 this way :

a = malloc(rows * sizeof(int *));
if(a==NULL){fprintf(stderr,"out of memory...i will fail\n");}
int *t = malloc(rows * width * sizeof(int));
if(t==NULL){fprintf(stderr,"out of memory...i will fail\n");}
for(i = 0; i < rows; ++i)
  a[i] = &t[i * width];

注意:malloc does not initialize memory to 0 !

您似乎想将一个二维数组分布到多个进程中。查看 MPI_Scatterv() here .看this question也是。

如果您想了解更多有关二维数组和 MPI 的信息,请查看 here .

您可能会找到 MPI_Scatterv 的基本示例 here .

我将 #define S 8 更改为 #define SQUARE_SIZE 42。最好给出描述性的名称。

这是使用 MPI_Scatterv() 的工作代码!

#include <mpi.h>
#include <iostream> 
#include <cstdlib>

using namespace std;

#define SQUARE_SIZE 42

MPI_Status status;

int main(int argc, char *argv[])
{
    int numtasks, taskid;
    int i, j, k = 0;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &taskid);
    MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

    int rows, offset, remainPart, orginalRows, height, width;
    int **a;

    height = width = SQUARE_SIZE;

    //on rank 0, let's build a big mat of int
    if(taskid == 0){ 
        a=new int*[height]; 
        int *t =new int[height * width];
        for(i = 0; i < height; ++i)
            a[i] = &t[i * width];
        for(i=0; i<height; i++)
            for(j=0; j<width; j++)
                a[i][j] = ++k;
    }

    //for everyone, lets compute numbers of rows, numbers of int and displacements for everyone. Only 0 will use these arrays, but it's a practical way to get `rows` 
    int nbrows[numtasks];
    int sendcounts[numtasks];
    int displs[numtasks];
    displs[0]=0;
    for(i=0;i<numtasks;i++){
        nbrows[i]=height/numtasks;
        if(i<height%numtasks){
            nbrows[i]=nbrows[i]+1;
        }
        sendcounts[i]=nbrows[i]*width;
        if(i>0){
            displs[i]=displs[i-1]+sendcounts[i-1];
        }
    }
    rows=nbrows[taskid];

    //scattering operation. 
    //The case of the root is particular, since the communication is not to be done...Hence, the flag MPI_IN_PLACE is used.
    if(taskid==0){
        MPI_Scatterv(&a[0][0],sendcounts,displs,MPI_INT,MPI_IN_PLACE,0,MPI_INT,0,MPI_COMM_WORLD);
    }else{
        //allocation of memory for the piece of mat on the other nodes.
        a=new int*[rows];
        int *t =new int[rows * width];
        for(i = 0; i < rows; ++i)
            a[i] = &t[i * width];

        MPI_Scatterv(NULL,sendcounts,displs,MPI_INT,&a[0][0],rows*width,MPI_INT,0,MPI_COMM_WORLD);
    }
    //printing, one proc at a time
    if(taskid>0){
        MPI_Status status;
        MPI_Recv(NULL,0,MPI_INT,taskid-1,0,MPI_COMM_WORLD,&status);
    }
    cout<<"rank"<< taskid<<" Rows : "<<rows<<" Width : "<<width<<endl;

    for(i=0; i<rows; i++)
    {
        for(j=0; j<width; j++)
            cout<<a[i][j]<<"\t";
        cout<<endl;
    }
    if(taskid<numtasks-1){
        MPI_Send(NULL,0,MPI_INT,taskid+1,0,MPI_COMM_WORLD);
    }

    //freeing the memory !

    delete[] a[0];
    delete[] a;

    MPI_Finalize();

    return 0;
}

编译:mpiCC main.cpp -o main

运行:mpiexec -np 3 main

关于c++ - MPI 中的动态内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25628321/

相关文章:

c++ - 多次调用MPI_Bcast是不是错了?

c++ - 奇怪的 C++ 线程函数调用

c++ - 为什么 reinterpret_cast 不将 'unsigned char' 转换为 'char' ?

c++ - 如果 vector 包含重复,则此函数应返回 true。知道为什么它不起作用吗?

c - 我怎样才能生成这样的 map ?

c - 如何初始化char指针数组,以避免垃圾值?

parallel-processing - 给定 MPI_Request 数组的 MPI_Waitall() 行为可能具有用于异步发送/接收的未初始化插槽

c++ - 为什么 WindowStateChange 事件对我不起作用

c - 我无法编译具有汇编语言指令的程序

c++ - cout 最慢的处理器 MPI