MPI是Message Passing Interface的简称,通过这个协议可以在各个进程——尤其是分布式内存进程——间能够进行通信,交流消息共同完成一个任务。

进行mpi编程的基本流程如下

首先要载入头文件

Fortran 77:
    include 'mpif.h' 
Fortran 90:
    use mpi 
C/C++:
    #include "mpi.h" 

第二步是初始化MPI环境

复制代码
Fortran 77/90:
    Call MPI_INIT(ierror)
其中integer ierror
C:
    int MPI_Init(int *argc, char ***argv); 
C++:
    int MPI::Init(int *argc, char ***argv); 
复制代码

第三步是获知参与并行的核的总数

复制代码
Fortran 77/90:
    Call MPI_COMM_SIZE(comm, size, ierror)
其中integer comm, size, ierror
C:
    int MPI_Comm_size (MPI_Comm comm, int *size); 
C++:
    int MPI::COMM_WORLD.Get_size( ); 
复制代码

第四步是得知自己所在的进程的序列号

复制代码
Fortran 77/90:
    Call MPI_COMM_RANK(comm, rank, ierror)
其中 integer comm, rank, ierror
C:
    int MPI_Comm_rank(MPI_Comm comm, int *rank); 
C++:
    int MPI::COMM_WORLD.Get_rank( ); 
复制代码

进行相关计算后

第五步是结束MPI环境

复制代码
Fortran 77/90:
     Call MPI_FINALIZE(ierror)
其中integer ierror
C:
     int MPI_Finalize(); 
C++:
     MPI::Finalize(); 
复制代码

还有两个不常用的方法

计算逝去的时间

Fortran 77/90:
    double precision MPI_WTIME() 
C:
    double MPI_Wtime(); 
C++:
    double MPI::Wtime(); 

和中止MPI环境

复制代码
Fortran:
    Call MPI_ABORT(comm, errorcode, ierror)
其中integer comm, errorcode, ierror
C:
    int MPI_Abort(MPI_Comm comm int errorcode ); 
C++:
    MPI::COMM_WORLD.Abort( int errorcode ); 
复制代码

MPI的数据类型则包括以下几种

C data type

MPI data type

charMPI_CHAR
short intMPI_SHORT
intMPI_INT
long intMPI_LONG
floatMPI_FLOAT
doubleMPI_DOUBLE
long doubleMPI_LONG_DOUBLE

Fortran data type

MPI data type

INTEGERMPI_INTEGER
REALMPI_REAL
REAL*8MPI_REAL8
DOUBLE PRECISIONMPI_DOUBLE_PRECISION
COMPLEXMPI_COMPLEX
LOGICALMPI_LOGICAL
CHARACTERMPI_CHARACTER

通常所用的消息交换方法有以下几种

MPI_SEND&MPI_RECV

复制代码
Fortran 77/90:
    Call MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERROR)
其中<type> BUF(*);INTEGER COUNT, DATATYPE, DEST, TAG, COMM, IERROR
C:
    int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest,int tag, MPI_Comm comm)
C++:
    MPI::Comm::Send(const void* buf, int count, const MPI::Datatype& datatype, int dest, int tag)
复制代码
复制代码
Fortran 77/90:
    Call MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS, IERROR)
其中<type> BUF(*);INTEGER COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS(MPI_STATUS_SIZE),IERROR

C:
    int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source,int tag, MPI_Comm comm, MPI_Status *status)
C++:
    MPI::Comm::Recv(void* buf, int count, const MPI::Datatype& datatype,int source, int tag, MPI::Status& status)
复制代码

这一组方法是阻塞式的,也就是会导致程序等待直到收到对应消息,所以有可能会发生程序死锁例如

复制代码
if (myid==0)
{
 MPI_RECV(a,100,MPI_INTEGER,0,10,comm, status)
 MPI_SEND(b,100,MPI_INTEGER,1,11,comm,status)
}
else
{
 MPI_RECV(a,100,MPI_INTEGER,0,11,comm,status)
 MPI_SEND(b,100,MPI_INTEGER,0,10,comm,status)
}
复制代码

还有Scatter&Gather

复制代码
Fortran 77/90:
    MPI_SCATTER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR)
其中<type> SENDBUF(*), RECVBUF(*); INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR
C:
    int MPI_Scatter(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root,MPI_Comm comm)
C++:
    MPI::Comm::Scatter(const void* sendbuf, int sendcount, const MPI::Datatype& sendtype, void* recvbuf, int recvcount,
const MPI::Datatype& recvtype, int root)
复制代码

 

复制代码
Fortran 77/90:
    Call MPI_GATHER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR)
其中<type> SENDBUF(*), RECVBUF(*);INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR
C:
    int MPI_Gather(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)
C++:
    MPI::Comm::Gather(const void* sendbuf, int sendcount, const MPI::Datatype& sendtype, void* recvbuf, int recvcount,
const MPI::Datatype& recvtype, int root)
复制代码

以下是例子

Fortran的

复制代码
Program mpitest
  use mpi
  Implicit None
  Integer,Parameter :: row=5000
  Integer,Parameter :: col=5000
  Real(Kind=8) :: mat_a(row,col),mat_b(row,col),mat_c(row,col)
  Integer :: myid,numprocs,rc,ierr,iprovided
  Integer(kind=sp) :: startcol,endcol,colsn
  Integer(kind=sp) :: i,j,k
  Call MPI_INIT(ierr)
  Call MPI_COMM_RANK(MPI_COMM_WORLD,myid,ierr)
  Call MPI_COMM_SIZE(MPI_COMM_WORLD,numprocs,ierr)
  mat_a=0.0d0
  mat_b=0.0d0
  mat_c=0.0d0
  colsn=col/numprocs
  startcol=colsn*myid+1
  endcol=colsn*(myid+1)
  If (myid==0) Then
     mat_a=100.0d0
     mat_b=80.0d0
  End If
  Call MPI_SCATTER(mat_a,colsn*row,MPI_DOUBLE_PRECISION,mat_a,colsn*row,MPI_DOUBLE_PRECISION,0,MPI_COMM_WORLD,ierr)
  Call MPI_SCATTER(mat_b,colsn*row,MPI_DOUBLE_PRECISION,mat_b,colsn*row,MPI_DOUBLE_PRECISION,0,MPI_COMM_WORLD,ierr)
   mat_c(:,1:colsn)=mat_a(:,1:colsn)-mat_b(:,1:colsn)
  Call MPI_GATHER(mat_c(:,1:colsn),colsn*row,MPI_DOUBLE_PRECISION,mat_c,colsn*row,MPI_DOUBLE_PRECISION,0,MPI_COMM_WORLD,ierr)

  Call MPI_FINALIZE(rc)
  Stop
End Program mpitest
复制代码

C++的

复制代码
# include <cstdlib>
# include <iostream>
# include <ctime>
# include "mpi.h"

using namespace std;

int main ( int argc, char *argv[] );

//****************************************************************************80

int main ( int argc, char *argv[] )

{
    const int row=5000;
    const int col=5000;
    int myid;
    int nprocs;
    int colsn;
    int i,j,k;
     MPI::Init(argc,argv);
    myid=MPI::COMM_WORLD.Get_rank();
    nprocs=MPI::COMM_WORLD.Get_size();
    colsn=row/nprocs;
    double (*mat_a)[col];
    double (*mat_b)[col];
    double (*mat_c)[col];
    double (*tmp_a)[col];
    double (*tmp_b)[col];
    double (*tmp_c)[col];
    tmp_a=new double[colsn][col];
    tmp_b=new double[colsn][col];
    tmp_c=new double[colsn][col];
    if (myid==0)
    {
        mat_a=new double[row][col];
        mat_b=new double[row][col];
        mat_c=new double[row][col];
        for ( i = 0; i < row; i++ )
        {
            for ( j = 0; j < col; j++ )
            {
                mat_a[i][j]=100.0;
            }
        }
        for ( i = 0; i < row; i++ )
        {
            for ( j = 0; j < col; j++ )
            {
                mat_b[i][j]=80.0;
            }
        }
        for ( i = 0; i < row; i++ )
        {
            for ( j = 0; j < col; j++ )
            {
                mat_c[i][j]=0.0;
            }
        }
    }
    else
    {
        mat_a=new double[1][col];
        mat_b=new double[1][col];
        mat_c=new double[1][col];
        for ( i = 0; i < colsn; i++ )
        {
            for ( j = 0; j < col; j++ )
            {
                tmp_a[i][j]=0.0;
            }
        }
        for ( i = 0; i < colsn; i++ )
        {
            for ( j = 0; j < col; j++ )
            {
                tmp_b[i][j]=0.0;
            }
        }
        for ( i = 0; i < colsn; i++ )
        {
            for ( j = 0; j < col; j++ )
            {
                tmp_c[i][j]=0.0;
            }
        }


    }

    MPI::COMM_WORLD.Scatter(mat_a, colsn*col, MPI::DOUBLE, tmp_a, colsn*col,MPI::DOUBLE,0);
    MPI::COMM_WORLD.Scatter(mat_b, colsn*col, MPI::DOUBLE, tmp_b, colsn*col,MPI::DOUBLE,0);

    for (i=0;i<colsn;i++)
    {
         for (j=0;j<col;j++)
         {
             tmp_c[i][j]=tmp_a[i][j]+tmp_b[i][j];
         }
    }
  
    MPI::COMM_WORLD.Gather(tmp_c, colsn*col, MPI::DOUBLE, mat_c, colsn*col,MPI::DOUBLE,0);
    MPI::Finalize();
    return 0;
}
复制代码

教程

http://www.lam-mpi.org/tutorials/bindings/

http://www.amazon.com/Introduction-Parallel-Computing-Ananth-Grama/dp/0201648652

http://www.megashare.com/3146342