【MPI学习1】简单MPI程序示例
有了apue的基础,再看mpi程序多进程通信就稍微容易了一些,以下几个简单程序来自都志辉老师的那本MPI的书的第七章。
现在ubuntu上配置了一下mpich的环境:
http://www.cnblogs.com/liyanwei/archive/2010/04/26/1721142.html
注意,为了编译运行方便,在~/.bashrc文件中添加mpi的两个环境变量
设置完之后注意执行source ~/.bashrc命令
程序1 计时功能
主要用到的MPI_Wtime()这个函数
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include "mpi.h" 5 6 int main(int argc, char *argv[]) 7 { 8 int err = 0; 9 double t1, t2; 10 double tick; 11 int i; 12 13 MPI_Init(&argc, &argv); 14 t1 = MPI_Wtime(); 15 t2 = MPI_Wtime(); 16 if (t2-t1>0.0 || t2-t1<0.0) { 17 err++; 18 fprintf(stderr, "two successive calls to MPI_Wtime gave strange results: (%f)(%f)\n", t1, t2); 19 } 20 21 for( i=0; i<10; i++) 22 { 23 t1 = MPI_Wtime(); 24 sleep(1); 25 t2 = MPI_Wtime(); 26 if (t2-t1>=(1-0.1) && t2-t1<=5) { 27 break; 28 } 29 if (t2-t1>5.0) { 30 i = 9; 31 } 32 } 33 if (i==10) { 34 fprintf(stderr, "timer around sleep(1) did not give 1 second; gave %f\n", t2-t1); 35 err++; 36 } 37 tick = MPI_Wtick(); 38 if (tick>1.0 || tick<0.0) { 39 err++; 40 fprintf(stderr, "MPI_Wtick gave a strange result:(%f)\n", tick); 41 } 42 MPI_Finalize(); 43 }
执行结果如下(在程序中故意设定了触发问题):
程序2 进程间数据接力传送
这里主要是MPI_Send和MPI_Recv两个函数,发送和接受来自其他进程的消息
代码如下:
1 #include <stdio.h> 2 #include "mpi.h" 3 4 int main(int argc, char *argv[]) 5 { 6 int rank, value, size; 7 MPI_Status status; 8 MPI_Init(&argc, &argv); 9 MPI_Comm_rank(MPI_COMM_WORLD, &rank); /*当前进程在MPI_COMM_WORLD这个通信组下面 编号是多少*/ 10 MPI_Comm_size(MPI_COMM_WORLD, &size); /*MPI_COMM_WORLD这个通信组下面 有多少个进程*/ 11 do { 12 if (rank==0) { 13 fprintf(stderr, "\nPlease give new value="); 14 scanf("%d",&value); 15 fprintf(stderr, "%d read <-<- (%d)\n",rank,value); 16 /*必须至少有两个进程的时候 才能进行数据传递*/ 17 if (size>1) { 18 MPI_Send(&value, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD); 19 fprintf(stderr, "%d send (%d)->-> %d\n", rank,value,rank+1); 20 } 21 } 22 else { 23 MPI_Recv(&value, 1, MPI_INT, rank-1, 0, MPI_COMM_WORLD, &status); 24 fprintf(stderr, "%d receive(%d)<-<- %d\n",rank, value, rank-1); 25 if (rank<size-1) { 26 MPI_Send(&value, 1, MPI_INT, rank+1, 0, MPI_COMM_WORLD); 27 fprintf(stderr, "%d send (%d)->-> %d\n", rank, value, rank+1); 28 } 29 } 30 MPI_Barrier(MPI_COMM_WORLD); 31 }while(value>=0); 32 MPI_Finalize(); 33 }
执行结果如下:
这里注意运行时候,参数 -np 4的意思是设置开启4个进程
程序3 进程间互相发送数据
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include "mpi.h" 4 5 void Hello(void); 6 7 int main(int argc, char *argv[]) 8 { 9 int me, option, namelen, size; 10 char process_name[MPI_MAX_PROCESSOR_NAME]; 11 MPI_Init(&argc, &argv); 12 MPI_Comm_rank(MPI_COMM_WORLD, &me); 13 MPI_Comm_size(MPI_COMM_WORLD, &size); 14 15 if (size < 2) { 16 fprintf(stderr, "system requires at least 2 processes"); 17 MPI_Abort(MPI_COMM_WORLD, 1); 18 } 19 MPI_Get_processor_name(process_name, &namelen); 20 fprintf(stderr, "Process %d is alive on %s\n", me, process_name); 21 MPI_Barrier(MPI_COMM_WORLD); 22 Hello(); 23 MPI_Finalize(); 24 } 25 26 void Hello() 27 { 28 int nproc, me; 29 int type = 1; 30 int buffer[2], node; 31 MPI_Status status; 32 MPI_Comm_rank(MPI_COMM_WORLD, &me); 33 MPI_Comm_size(MPI_COMM_WORLD, &nproc); 34 if (me==0) { 35 printf("\nHello test from all to all\n"); 36 fflush(stdout); 37 } 38 for(node = 0; node < nproc; node++) 39 { 40 if (node != me) { 41 buffer[0] = me; 42 buffer[1] = node; 43 MPI_Send(buffer, 2, MPI_INT, node, type, MPI_COMM_WORLD); 44 MPI_Recv(buffer, 2, MPI_INT, node, type, MPI_COMM_WORLD, &status); 45 if (buffer[0] != node || buffer[1] != me) { 46 fprintf(stderr, "Hello: %d != %d or %d != %d\n", buffer[0], node, buffer[1], me); 47 printf("Mismatch on hello process ids; node = %d\n",node); 48 } 49 printf("Hello from %d to %d\n",me,node); 50 fflush(stdout); 51 } 52 } 53 }
执行结果如下:
程序4 多个进程向一个进程发送消息
1 #include "mpi.h" 2 #include <stdio.h> 3 4 int main(int argc, char *argv[]) 5 { 6 int rank, size, i, buf[1]; 7 MPI_Status status; 8 MPI_Init(&argc, &argv); 9 MPI_Comm_rank(MPI_COMM_WORLD, &rank); 10 MPI_Comm_size(MPI_COMM_WORLD, &size); 11 if (rank==0) { 12 /*主进程不断接收从各个进程发送过来的消息*/ 13 for(i=0; i<5*(size-1); i++) 14 { 15 MPI_Recv(buf, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); 16 printf("Msg=%d from %d with tag %d\n",buf[0], status.MPI_SOURCE, status.MPI_TAG); 17 } 18 } 19 else { 20 /*其他进程向主进程发送消息*/ 21 for(i=0; i<5; i++) 22 { 23 buf[0] = rank+i; 24 MPI_Send(buf, 1, MPI_INT, 0, i, MPI_COMM_WORLD); 25 } 26 } 27 MPI_Finalize(); 28 }
执行结果如下:
上面几个程序的核心是MPI_Send和MPI_Recv,在上面的程序中来看,这两个函数都是阻塞函数。
因此,进程之间如果有消息的互相发送和接收,就可能会产生死锁现象。
这个书上P47~49有说明,但是由于涉及到MPI通讯模式的问题,因此留到后面再看。
这几个程序目的是为了数据mpi的编译运行环境以及一些基本函数,后面开始学习并行程序的设计方法。