MPI中的动态内存分配 [英] Dynamic Memory Allocation in MPI

查看:377
本文介绍了MPI中的动态内存分配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是MPI的新手。我写了一个简单的代码来显示使用多进程的矩阵。假设我有一个8x8的矩阵,并启动MPI程序与4个进程,第一2行将打印我的第一个过程第二组2行将打印第二线程等等通过划分自己。

I am new to MPI. I wrote a simple code to display a matrix using multiple process. Say if I have a matrix of 8x8 and launching the MPI program with 4 processes, the 1st 2 rows will be printed my 1st process the 2nd set of 2 rows will be printed by 2nd thread so on by dividing itself equally.

#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],并删除

This is my complete code, here I have allocated the memory dynamically for 'a', while printing a[i][j], under the else part, I am getting runtime error. If I change the dynamic memory allocation to static like changing int **a to int a[N][N] and removing

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

它可以完美地工作。

推荐答案

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

There are at least two ways to dynamically allocate a 2D array.

第一个是@HRoid:一次一个。请在此查看获取计划。

The first one is the one of @HRoid : each row is allocated one at a time. Look here for getting an scheme.

第二个是由@Claris建议的,它将确保数据在内存中是连续的。这是许多MPI操作所需要的...它也需要像FFTW(2D快速傅里叶变换)或Lapack(线性代数的密集矩阵)。您的程序可能会失败

The second one is suggested by @Claris, and it will ensure that the data is contiguous in memory. This is required by many MPI operations...it is also required by libraries like FFTW (2D fast fourier transform) or Lapack (dense matrices for linear algebra). Your program may fail at

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

如果 S> 1 尝试发送行结束后的项目n° offset ...这可能会触发分段错误或未定义的行为。

if S>1, this program will try to send items that are after the end of the line n°offset...That may trigger a segmentation fault or undefined behavior.

您可以分配数组

You may allocate your array 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 不将内存初始化为0

看起来你想在一个2D数组上传播许多进程。查看 MPI_Scatterv() 这里。查看这个问题

It seems that you want to spread a 2D array over many process. Look at MPI_Scatterv() here. Look at this question too.

如果你想更多地了解2D数组和MPI,看看此处

If you want to know more about 2D arrays and MPI, look here.

您可以在此处此处找到一个MPI_Scatterv的基本示例。

You may find a basic example of MPI_Scatterv here.

我为 #define SQUARE_SIZE 42 更改了 #define S 8 。它总是更好地给描述性的名称。

I changed #define S 8 for #define SQUARE_SIZE 42. It's always better to give descriptive names.

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

And here is a working code using 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

这篇关于MPI中的动态内存分配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆