至于原理,在这里我就不再叙述了,网上有很多资料或者教材都写得比较详细。这里仅仅介绍如何用C语言编写利用MPI_SEND和MPI_RECV实现Jacobi迭代。
#include <stdio.h>
#include "mpi.h"
#define totalsize 16 //定义常量,16行
#define mysize totalsize/4 //定义常量,4个进程,每块有totalsize/4列
#define steps 10//定义常量,设置迭代次数
int main(int argc,char **argv ){
int n, myid, numprocs, i, j,rc; //声明变量
float a[totalsize][mysize+2],b[totalsize][mysize+2];//定义二维数组
float temp[totalsize]; //定义一个一维临时数组
int begin_col,end_col,ierr;//声明变量
MPI_Status status;
MPI_Init( &argc, &argv );//初始化MPI
MPI_Comm_rank( MPI_COMM_WORLD, &myid);//获取进程号
MPI_Comm_size( MPI_COMM_WORLD, & numprocs);//获取当前通信域的进程总数
fprintf(stderr,"Process %d of %d is alive\n",myid,numprocs);//打印
//数组初始化
/*
每个进程各自初始化自己的部分,先将所有元素全部赋值为0.0
C语言中,数组下标从0开始
*/
for (i=0;i < totalsize;i++){
for (j=0;j < mysize+2;j++)
a[i][j]=0.0;
}
/*
0号进程,将第2列全部赋值为8.0(实际上是数据矩阵的第一列)
*/
if(myid==0){
for(i=0;i < totalsize;i++)
a[i][1]=8.0;
}
/*
3号进程,将倒数第2列全部赋值为8.0(实际上是数据矩阵的最后一列)
*/
if(myid==3) {
for(i=0;i<totalsize;i++)
a[i][mysize]=8.0;
}
/*
每一个进程,将矩阵第1行和最后一行全部赋值为8.0
*/
for (j=1;j < mysize+1;j++){
a[0][j]=8.0;
a[totalsize-1][j]=8.0;
}
//Jacobi迭代部分
for (n=1;n<=steps;n++){
/*从右侧的邻居得到数据
C语言中按行存储
所以要先定义一个一维临时数组来接收数据
*/
if (myid<3){
MPI_Recv(&temp[0],totalsize,MPI_FLOAT,myid+1,10,MPI_COMM_WORLD,&status);
for(i=0;i<totalsize;i++){
a[i][mysize+1]=temp[i];//a[i][mysize+1]为块的最后一列
}
}
/*向左侧的邻居发送数据
先将块的第2列提取到临时数组,然后再按顺序发送出去
*/
if (myid>0){
for(i=0;i<totalsize;i++){
temp[i]=a[i][1];//a[i][1]为块的第2列
}
MPI_Send(&temp[0],totalsize,MPI_FLOAT,myid-1,10,MPI_COMM_WORLD);
}
//向右侧的邻居发送数据
if (myid<3){
for(i=0;i<totalsize;i++){
temp[i]=a[i][mysize];//a[i][mysize]为块的倒数第2列
}
MPI_Send(&temp[0],totalsize,MPI_REAL,myid+1,10,MPI_COMM_WORLD);
}
//从左侧的邻居得到数据
if (myid>0){
MPI_Recv(&temp[0],totalsize,MPI_REAL,myid-1,10,MPI_COMM_WORLD,&status);
for(i=0;i<totalsize;i++){
a[i][0]=temp[i];//a[i][0]为块的第一列
}
}
begin_col=1,end_col=mysize;//开始列和结束列的列号
if(myid==0){
begin_col=2;//若为0号进程,开始列为块的第3列
}
if(myid==3){
end_col=mysize-1;//若为3号进程,结束列为块的倒数第3列倒数,mysize+2-1-2=mysize-1
}
//第一行和最后一行也不参与迭代,所以i从1(第二行)到totalsize-1(最后一行)-1(下标)=totalsize-2
for(i=1;i<=totalsize-2;i++){
for(j=begin_col;j<=end_col;j++){
b[i][j]=(a[i][j+1]+a[i][j-1]+a[i+1][j]+a[i-1][j])*0.25;//迭代计算
}
}
//更新a矩阵 (将b中的元素值分别对应赋给a矩阵)以便进行下一次迭代
for(i=1;i<=totalsize-2;i++){
for(j=begin_col;j<=end_col;j++){
a[i][j]=b[i][j];
}
}
}//迭代结束
/*输出结果*/
fprintf(stderr,"\nProcess %d :\n",myid);
//此处没有打印矩阵的第一行第一列,最后一行最后一列
for(i=1;i<totalsize-1;i++){
for(j=begin_col;j<=end_col;j++){
fprintf(stderr,"%.2f\t",a[i][j]);//打印.(保留两位小数输出)
}
fprintf(stderr,"\n");//打印完一行之后换行
}
fprintf(stderr,"\n");
MPI_Finalize( );//结束MPI
}