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

char MPI_CHAR
short int MPI_SHORT
int MPI_INT
long int MPI_LONG
float MPI_FLOAT
double MPI_DOUBLE
long double MPI_LONG_DOUBLE

Fortran data type

MPI data type

INTEGER MPI_INTEGER
REAL MPI_REAL
REAL*8 MPI_REAL8
DOUBLE PRECISION MPI_DOUBLE_PRECISION
COMPLEX MPI_COMPLEX
LOGICAL MPI_LOGICAL
CHARACTER MPI_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