基于c与MPI并行程序初步
第一片儿小代码:
- #include "mpi.h"
- #include
- #include
- void main(argc,argv)
- int argc;
- char *argv[];
- {
- int myid, numprocs;
- int namelen;
- char processor_name[MPI_MAX_PROCESSOR_NAME];
- MPI_Init(&argc,&argv);
- MPI_Comm_rank(MPI_COMM_WORLD,&myid);
- MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
- MPI_Get_processor_name(processor_name,&namelen);
- fprintf(stderr,"Hello World! Process %d of %d on %s\n",
- myid, numprocs, processor_name);
- MPI_Finalize();
- }
MPI程序的框架结构

在MPI-1中,共有128个调用接口,在MPI-2中有287个,但是理论上,MPI所有通信功能可以用其中6个基本的调用实现。
MPI调用的说明格式

对于有参数的MPI调用,MPI首先给出一种独立于具体语言的说明,对各个参数的性质进行介绍,然后在给出它相对于C的原型说明,在MPI-2中还给出了C++形式的说明.MPI对参数说明的方式有三种,分别是IN OUT和INOUT,它们的含义分别是:
IN 输入 调用部分传递给MPI的参数,MPI除了使用该参数外不允许对这一参数做任何修改。
OUT 输出 MPI返回给调用部分的结果参数,该参数的初始值对MPI没有任何意义。
INOUT 输入输出 调用部分首先将该参数传递给MPI MPI对这一参数引用修改后,将结果返回给外部调用,该参数的初始值和返回结果都有意义。
MPI在最大范围内避免使用INOUT参数,因为这种参数容易出错,特别是对标量参数。如果一个隐含对象的句柄,作为一个参数,这个句柄在调用前后作为参数没有改变,但是句柄指向的对象发生了改变,这一参数仍然是OUT或者INOUT。某些参数被用作IN同时被别的东东用作OUT,虽然在语义上不是同一个输入输出,但是语法上记为INOUT
两种调用方法:
独立于语言的说明 对于这一个调用没有参数说明
- MPI_INIT()
C语言的说明 对于C语言调用 需要给出参数argc和argv 注意这里给出的是argc和argv。
- int MPI_Init(int *argc,char ***argv)
对于不同的数据类型,可以用相同的调用。对于MPI的调用,允许不同的数据类型使用相同的调用,不如对于数据发送操作,整型,实型,字符型等都用一个相同的调用MPI_SEND.
MPI开始结束很简单,用下面的语句就可以啦;
1.MPI初始化
- MPI_INIT()
- int MPI_Init(int *argc, char ***arg
- MPI_INIT(IERROR)
- INTEGER IERROR
2.MPI结束
- MPI_FINALIZE()
- int MPI_Finalize(void)
- MPI_FINALIZE(IERROR)
- INTEGER IERROR
结束时必不可少的,否则后果自负~咔咔!
3.当前进程标识
- MPI_COMM_RANK(comm,rank)
- IN comm //该进程所在的通信域 句柄
- OUT rank //调用进程在comm中的标识号
- int MPI_Comm_rank(MPI_Comm comm, int *rank)
- MPI_COMM_RANK(COMM,RANK,IERROR)
- INTEGER COMM,RANK,IERROR
这个进程返回的是调用进程在给定的通信域中的进程标识号,有了这一标号,不同的进程就可以将自己和其他的进程去别开来,实现各进程的并行和协作。
4.通信与包含的进程数
- MPI_COMM_SIZE(comm,size)
- IN comm //通信域 句柄
- OUT size //通信域comm内包括的进程数 整数
- int MPI_Comm_size(MPI_Comm comm, int *size)
- MPI_COMM_SIZE(COMM,SIZE,IERROR)
- INTEGER COMM,SIZE,IERROR
这一调用返回给定的通信域中所包括的进程的个数 不同的进程通过这一调用得知在给
的通信域中一共有多少个进程在并行执行.
5.消息发送
- MPI_SEND(buf,count,datatype,dest,tag,comm)
- IN buf //发送缓冲区的起始地址(可选类型)这是以数据类型为单位指定消息的长度,独立于具体实现,更加接近于用户观点。
- IN count //将发送的数据的个数(非负整数)
- IN datatype //发送数据的数据类型(句柄)可以是MPI预定义类型,也可以是用户自定义类型。
- IN dest //目的进程标识号(整型)
- IN tag //消息标志(整型),把本次发送的消息和本进程向同一目的进程发送的其他消息区别开来!
- IN comm //通信域(句柄)
- int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm
- comm)
- MPI_SEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERROR)
- BUF(*)
- INTEGER COUNT, DATATYPE, DEST, TAG, COMM, IERROR
6.消息接收
- MPI_RECV(buf,count,datatype,source,tag,comm,status)
- OUT buf //接收缓冲区的起始地址(可选数据类型)
- IN count //最多可接收的数据的个数(整型)
- IN datatype //接收数据的数据类型(句柄)MPI和用户均可定义
- IN source //接收数据的来源即发送数据的进程的进程标识号(整型)
- IN tag //消息标识 与相应的发送操作的表示相匹配相同(整型)
- IN comm //本进程和发送进程所在的通信域(句柄)
- OUT status //返回状态 (状态类型)
- int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag,
- MPI_Comm comm, MPI_Status *status)
- MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, STATUS,
- IERROR)
- BUF(*)
- INTEGER COUNT, DATATYPE, SOURCE, TAG, COMM,
7.一个简单的发送和接收的例子
- #include "mpi.h"
- main( argc, argv )
- int argc;
- char **argv;
- {
- char message[20];
- int myrank;
- MPI_Init( &argc, &argv );
- /* MPI程序的初始化*/
- MPI_Comm_rank( MPI_COMM_WORLD, &myrank );
- /* 得到当前进程的标识*/
- if (myrank == 0) /* 若是 0 进程*/
- {
- /* 先将字符串拷贝到发送缓冲区message中 然后调用MPI_Send语句将它发出 用
- strlen(message)指定消息的长度 用MPI_CHAR指定消息的数据类型 1指明发往进程1 使
- 用的消息标识是99 MPI_COMM_WORLD是包含本进程 进程0 和接收消息的进程 进
- 程1 的通信域 发送方和接收方必须在同一个通信域中 由通信域来统一协调和控制消息
- 的发送和接收*/
- strcpy(message,"Hello, process 1");
- MPI_Send(message, strlen(message), MPI_CHAR, 1,
- 99,MPI_COMM_WORLD);
- }
- else if(myrank==1) /* 若是进程 1 */
- {
- /*进程1直接执行接收消息的操作 这里它使用message作为接收缓冲区 由此可见 对于同
- 一个变量 在发送进程和接收进程中的作用是不同的 它指定接收消息的最大长度为20 消
- 息的数据类型为MPI_CHAR字符型 接收的消息来自进程0 而接收消息携带的标识必须为
- 99 使用的通信域也是MPI_COMM_WORLD 接收完成后的各种状态信息存放在status中
- 接收完成后 它直接将接收到的字符串打印在屏幕上 */
- MPI_Recv(message, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, &status);
- printf("received :%s:", message);
- }
- MPI_Finalize();
- /* MPI程序结束*/
- }

MPI_Send和MPI_Recv的第一个参数都应该是地址 你直接用变量名应该不可以 &message