一、学习的大致内容:
1. MPI概述
2. MPI实现
3. 终极测试
注:此部分内容提炼自《并行程序设计导论》第三章
二、MPI的概述:
- MPI的宏观理解:
MPI的英文全称为:Message Passing Interface
啥意思捏?就是个消息传递的接口,或者说是消息中转服务商。
假设,我们生活在上世纪80年代,只能写信沟通,我(进程A)想写一封情书(信息)给你(进程B),我写好了情书后(生成好信息),我交给邮递员(MPI函数)帮我装入信封(信息封装),邮递员交给邮政局(MPI的内部缓存),邮政局交给邮递员(MPI函数)再交给你(进程B),在交给你之前,邮递员还会帮你拆开信封(解封)只将里面的情书(信息)传递给你(进程B)。
其实与计算机网络中应用层之间信息的转递是一个模式,只是MPI不需要像网络层次结构那样层层封装传递。
- MPI现实理解:
在多进程程序中,两个进程可以通过调用函数来进行通信:一个进程发送函数,另一个接收函数。我们将使用消息传递的实现称为消息传递接口(MPI)。MPI并不是一种新的语言,它定义了一个可以被C、C++和Fortran程序调用的函数库
- 头文件
MPI.h
- 编译
$ mpicc 文件名.c -o 文件名.out
- 运行
$ mpirun -n 进程数 ./文件名.out
- 获取版本号
$ mpicc -v 或 mpiexec --version
三、MPI实现
我们通过调用一系列的MPI函数来实现多进程间的通信(MPI通信)
1. 开始与结束:
要使用MPI,必须对MPI进行初始化,可以理解为:要让邮递员帮你传情书得自己先建一个邮局。同样的,在你不需要继续使用MPI时,也需要结束MPI,释放MPI所占的资源
(过河拆桥,情定三生后就拆邮局,想想都刺激)
(0)MPI初始化判断: MPI_Initialized函数:
函数原型:
int MPI_Initialized(int* flag_p)
参数解释:
①int* flag_p:
flag_p
是指向flag
的指针。用来判断MPI系统是否已经初始化,若MPI已初始化则flag=true,反之flag=false。
作用:
唯一可在MPI_Init前使用的函数,用来检测MPI系统是否已经初始化。
(1)MPI初始化: MPI_Init函数:
函数原型:
int MPI_Init(int* argc_p,char*** argv_p){...}
参数解释:
①int* argc_p:
argc_p
是指向argc
的指针,是main
函数中参数的继承(一般写NULL即可)。
②char*** argv_p:
argv_p
是指向argv
的指针,是main
函数中参数的继承(一般写NULL即可)。
③返回值:
返回值为int
类型的错误码,在大部分情况下,我们忽略这些错误码。亦可以利用MPI_Error_string
函数,通过输入错误码返回错误信息的方式得到错误信息。
作用:
初始化MPI。具体的:为MPI分配缓存,设置MPI中所有进程的序号,等。
(2)MPI结束: MPI_Finalize函数:
函数原型:
int MPI_Finalize(void){...}
参数解释:
返回值:错误码
作用:
释放MPI占用的资源
(3)MPI框架:
有了上述(1)MPI_Init,(2)MPI_Finalize俩函数,则我们可以初步得到一个利用MPI程序设计的框架,即:
int main(int* argc,char** argv){
/*No MPI Calls Before This*/
MPI_Init(NULL,NULL);
....
MPI_Finalize();
/*No MPI Calls After This*/
return 0;
}
2. 通信子Communicator
(1)通信子
概念:
通信子就是一个集合,一个由多个可以相互通信的进程组成的集合。
MPI通信子类型:
MPI_Comm
,其值为:MPI_COMM_WORLD
(2)获得通信子内进程个数的函数: MPI_Comm_size函数
函数原型:
int MPI_Comm_size(MPI_Comm comm,int* Comm_sz_p){...}
参数解释:
①MPI_Comm comm: /*输入*/
comm
是MPI通信子的名称,其名称为MPI_COMM_WORLD不变
②int* comm_sz_p: /*输出*/
comm_sz_p
是一个指针,用来返回通信子大小(进程总数)。
③返回值: /*输出*/
错误码。
函数作用:
用comm_sz_p
来返回 名叫comm
的通信子大小
(3)获得当前调用此函数的进程号: MPI_Comm_rank函数
函数原型:
int MPI_Comm_rank(MPI_Comm comm,int* my_rank_p){...}
参数解释:
①MPI_Comm comm /*输入*/
同上,通信子名称:MPI_COMM_WORLD
②int* my_rank_p /*输出*/
my_rank_p
是一个指针,用来返回当前调用此函数的进程在通信子中的序号。
③返回值: /*输出*/
错误码。
函数作用:
用my_rank_p
来返回调用此函数的进程在名叫comm
的通信子中的序号。
(4)MPI框架:
有了通信子的新知识,我可以在1-(3)MPI框架的基础上扩展为一个更细的框架。
由于我们在MPI调用中,不可避免的要大量使用通信子名(MPI_COMM_WORLD
),通信子大小(comm_sz
),当前进程号(my_rank
),则我们将MPI框架构造如下:
#include <stdio.h>//C语言基本头文件
#include <mpi.h>//MPI头文件
/*---设置全球变量----*/
MPI_Comm comm;
int comm_sz;
int my_rank;
/*---SET GLOBAL VARIABLE---*/
int main(int argc,char** argv){
/*No MPI calls before this*/
MPI_Init(NULL,NULL);
comm = MPI_COMM_WORLD;//Set comm
MPI_Comm_size(comm,&comm_sz);//get communicator size
MPI_Comm_rank(comm,&my_rank);//get this processs rank
...//you can coding whatever you want
MPI_Finalize();
/*No MPI calls after this*/
}