启动非阻塞通信
MPI_START(request)
INOUT request 非阻塞通信对象(句柄)
int MPI_Start(MPI_Request *request)
MPI_START(REQUEST,IERROR)
INTEGER REQUEST ,IERROR

讲解:

一个重复非阻塞通信在创建后处于非活动状态,没有活动的通信附在该对象中。一个使用重复非阻塞通信的对象(发送或接收)使用MPI_START将其激活。
request参数是一个由前面介绍的初始化非阻塞重复调用返回的句柄。MPI_START调用之前,该对象处于非激活状态,一旦使用该调用,该调用成为激活状态。如果这是一个接收就绪模式发送请求,则在该调用之前应该先有一个匹配的接收操作被启动。通信缓冲区在该调用后应该被禁止访问,直到操作完成。
一个用MPI_SEND_INIT创建的非阻塞重复通信对象来调用MPI_START产生的通信和用MPI_ISEND调用产生的通信效果一样;一个用MPI_BSEND_INIT创建的非阻塞重复通信对象来调用MPI_START产生的通信和直接调用MPI_IBSEND产生的通信效果相同,其它的也一样。

MPI_STARTALL(count,array_of_requests)
IN count 开始非阻塞通信对象的个数 (整型)
IN array_of_requests 非阻塞通信对象数组(句柄队列)
int MPI_Startall(int count, MPI_Request *array_of_requests)
MPI_STARTALL(COUNT, ARRAY_OF_REQUESTS,IERROR)
INTEGER COUNT, ARRAY_OF_REQUESTS(*),IERROR


讲解:
一个MPI_STARTALL调用等价于对array_of_request表中的每一个非阻塞重复通信对象用MPI_START调用。一个由MPI_START或MPI_STARTALL调用开始的通信如同前面介绍的各种非阻塞通信一样,由MPI_WAIT或MPI_TEST调用来完成。这些调用的成功完成将使非阻塞通信对象处于非激活状态,但是该对象并未被释放,它可以被MPI_START或MPI_STARTALL重新激活。一个重复非阻塞通信对象可以用MPI_REQUEST_FREE来释放,MPI_REQUEST_FREE可以在重复非阻塞通信被创建以后的任何地方被调用,可是,只有当该对象成为非活动状态时才可以被取消。

由于在Jacobi迭代中,通信放在循环之内,要重复进行,因此可以用重复非阻塞通信来实现它。
 


program main
implicit none
include 'mpif.h'
integer totalsize,mysize,steps
parameter (totalsize=16)
parameter (mysize=totalsize/4,steps=10)

integer n, myid, numprocs, i, j,rc
real a(totalsize,mysize+2),b(totalsize,mysize+2)
integer begin_col,end_col,ierr
integer left,right,tag1,tag2
integer status(MPI_STATUS_SIZE,4)
integer req(4)


call MPI_INIT( ierr )
call MPI_COMM_RANK( MPI_COMM_WORLD, myid, ierr )
call MPI_COMM_SIZE( MPI_COMM_WORLD, numprocs, ierr )
print *, "Process ", myid, " of ", numprocs, " is alive"
C 数组初始化
do j=1,mysize+2
do i=1,totalsize
a(i,j)=0.0
end do
end do
do i=1,totalsize
a(i,1)=8.0
a(i,mysize+2)=8.0
end do
C 边界元素赋初值
if (myid .eq. 0) then
do i=1,totalsize
a(i,2)=8.0
end do
end if
if (myid .eq. 3) then
do i=1,totalsize
a(i,mysize+1)=8.0
end do
end if
do i=1,mysize+2
a(1,i)=8.0
a(totalsize,i)=8.0
end do

tag1=3
tag2=4

C 设置当前进程左右两侧的进程
if (myid .gt. 0) then
left=myid-1
else
left=MPI_PROC_NULL
end if
if (myid .lt. 3) then
right=myid+1
else
right=MPI_PROC_NULL
end if

C 设置迭代的开始和终止列
begin_col=2
end_col=mysize+1
if (myid .eq. 0) then
begin_col=3
endif
if (myid .eq. 3) then
end_col=mysize
endif

C 初始化重复非阻塞通信
call MPI_SEND_INIT(b(1,end_col),totalsize,MPI_REAL,right,tag1,
*MPI_COMM_WORLD,req(1),ierr)
call MPI_SEND_INIT(b(1,begin_col),totalsize,MPI_REAL,left,tag2,
*MPI_COMM_WORLD,req(2),ierr)

call MPI_RECV_INIT(a(1,1),totalsize,MPI_REAL,left,tag1,
* MPI_COMM_WORLD,req(3),ierr)
call MPI_RECV_INIT(a(1,mysize+2),totalsize,MPI_REAL,right,tag2,
* MPI_COMM_WORLD,req(4),ierr)
C 执行迭代
do n=1,steps
C 先计算需要通信的部分
do i=2,totalsize-1
b(i,begin_col)=(a(i,begin_col+1)+a(i,begin_col-1)+
* a(i+1,begin_col)+a(i-1,begin_col))*0.25
b(i,end_col)=(a(i,end_col+1)+a(i,end_col-1)+
*a(i+1,end_col)+a(i-1,end_col))*0.25
end do

C 激活非阻塞通信对象,启动4个非阻塞通信
call MPI_STARTALL(4,req,ierr)
C 计算剩余的迭代部分
do j=begin_col+1,end_col-1
do i=2,totalsize-1
b(i,j)=(a(i,j+1)+a(i,j-1)+a(i+1,j)+a(i-1,j))*0.25
end do
end do
do j=begin_col,end_col
do i=2,totalsize-1
a(i,j)=b(i,j)
end do
end do

C 完成非阻塞通信,非阻塞通信对象变为非活动态
call MPI_WAITALL(4,req,status,ierr)

end do
do i=2,totalsize-1
print *, myid,(a(i,j),j=begin_col,end_col)
end do

C 释放非阻塞通信对象
do i=1,4
CALL MPI_REQUEST_FREE(req(i),ierr)
end do
call MPI_FINALIZE(rc)
end