3.7.3 通信完成 |
函数MPI_WAIT和MPI_TEST用于完成一个非阻塞通信。一个操作的完成表示现在这个发送者可自由地修改在发送缓存(这个发送操作本身离开不改变的发送缓存的内容)中的数据。它不表示消息已被接收,而它可以被通讯子系统缓存。但是,如果使用一个同步模式的发送,那么发送操作的完成表示一个匹配接收被初始化了,并且这个匹配的接收最终将接收这个消息。
一个接收操作的完成表示这个接收缓存包含被接收的消息,接收者可以自由存取它,并设置状态对象。它不表示这个匹配发送操作已被完成(但当然表示这个发送已被初始化)。
我们将使用下面术语。一个null句柄是有值MPI_REQUEST_NULL的一个句柄。如果请求没有和任何正出发的通信(看3.9节)联结,那么对它的一个持续的请求和这个句柄是不活动的(inactive)。如果一个句柄既不是null也不是不活动的, 那么它是活动的。
MPI_WAIT(request, status)
INOUT request 请求(句柄)
OUT status 状态对象(状态类型)
int MPI_Wait(MPI_Request *request, MPI_Status *status)
MPI_WAIT(REQUEST, STATUS, IERROR)
INTEGER REQUEST, STATUS(MPI_STATUS_SIZE), IERROR
当由request识别的操作完成时, 对MPI_WAIT调用返回。如果和这个请求联结的通信对象已由一个非阻塞发送或接收调用创建,那么这个对象由对MPI_WAIT的调用解出分配并设置请求句柄为MPI_REQUEST_NULL。MPI_WAIT是一个非局部的操作。
调用在status中返回关于已完成操作的信息。一个接收操作的状态对象的内容能被以3.2.5节描述的方法存取。一个发送操作的状态对象可以被一个对MPI_TEST_CANCELLED(看3.8节)的调用来查寻。
允许用一个null或不活动的request参数调用MPI_WAIT。这种请况下,这个操作立刻返回。状态参数设为返回tag = MPI_ANY_TAG, source = MPI_ANY_SOURCE,也内部地被构成, 以便对MPI_GET_COUNT和MPI_GET_ELEMENTS的调用返回count=0。
基本原理. 这和一个长度列表在功能上等价于MPI_WAITALL, 并加一些优雅。 以这种方式设置状态以便阻止由于无效信息的存取造成的错误。
在一个MPI_IBSEND后的MPI_WAIT的成功返回隐含着用户的发送缓存能被再使用 ----例如, 数据已被发送出去或已被拷到与MPI_BUFFER_ATTACH联结的一个缓存。注意,这时,我们不再取消这个发送(看3.8节)。如果从来没有一个匹配接收登入,那么缓存不能被自由存取。这多少表明了对MPI_CANCEL(总能释放 被提交给通信子系统的程序空间)所叙述目的的计数。(基本原理结束)。
给实现者的建议. 在一个多线索环境, 对MPI_WAIT的一个调用应仅阻止调用 线索, 允许线索调度者调度另一个执行线索。(给实现的建议结束)。
MPI_TEST(request, flag, status)
INOUT request 通信请求(句柄)
OUT flag 如果操作完成则为真(逻辑型)
OUT status 状态对象(状态类型)
int MPI_Test(MPI_Request,*request, int *flag, MPI_Status *status)
MPI_TEST(REQUEST, FLAG, STATUS, IERROR)
LOGICAL FLAG
INTEGER REQUEST, STATUS(MPI_STATUS_SIZE), IERROR
如果由request识别的操作被完成, 那么对MPI_TEST的一个调用返回flag=true(真)。这时,状态变量设为包含关于已完成操作的信息;如果由一个非阻塞发送或接收创建这个通信,那么它被解出分配并设请求句柄为MPI_REQUEST_NULL。否则, 这个调用返回flag = false(假)。这时,状态对象的值无定义。MPI_TEST是一个局部操作。
一个接收操作的返回状态对象带有能以3.2.5节描述方式存取的信息。一个发送操作的状态对象带有被对MPI_TEST_CANCELLED(看3.8)的调用存取的信息。
允许用一个null或不活动的request参数调用MPI_TEST。这时操作返回flag =false(假)。
函数MPI_WAIT和MPI_TEST能被用于完成发送和接收。
给用户的建议. 非阻塞MPI_TEST调用的使用允许用户在一个单个执行的线索 内调用可选择的行为。一个事件驱动的线索调度器能与对MPI_TEST的周期调用 竟争。(给用户的建议结束)。
例子3.10 非阻塞操作和MPI_WAIT简单的使用方法。
CALL MPI_COMM_RANK(comm, rank, ierr)
IF(rank.EQ.0) THEN
CALL MPI_ISEND(a(1), 10, MPI_REAL, 1, tag, comm, request, ierr)
****给屏蔽延迟作一些计算****
CALL MPI_WAIT(request, status, ierr)
ELSE
CALL MPI_IRECV(a(1), 15, MPI_REAL, 0, tag, comm, request, ierr)
****给屏蔽延迟作一些计算****
CALL MPI_WAIT(request, status, ierr)
END IF
如果不为等待所联结通信的完成, 使用下面的操作能解出分配一个请求对象。
MPI_REQUEST_FREE(request)
INOUT request 通信请求(句柄)
int MPI_Request_free(MPI_Request *request)
MPI_REQUEST_FREE(REQUEST, IERROR)
INTEGER REQUEST, IERROR
为解出分配标记请求对象, 并设request为MPI_REQUEST_NULL。和这个请求联结一个正出发的通信将被允许完成。只在它完成后,这个请求将被解出分配。
基本原理. 因为在发送方的性能和方便的原因, 提供了MPI_REQUEST_FREE机制。(基本原理结束)。
给用户的建议. 一旦对MPI_REQUEST的一个调用释放一个请求, 用对MPI_WAIT或MPI_TEST的调用检查所联结通信的成功完成,这是不可能的。如果在通信期间一个错误后来发生,那么错误代码不能被返回给用户-这样的错误必须作为致命的。当使用MPI_REQUEST_FREE时, 怎样知道何时操作已被完成的问题出现。依赖程序的逻辑,程序用其他方法知道某个操作已被完成,这使MPI_REQUEST_FREE的使用成为实际。例如,当程序的逻辑是这样的,即接收者给被发送的消息发送一个回答时,释放激活的发送请求--回答的到达通知发送者发送已完成并能再使用这个发送缓存。当接收缓存没有方法检验这个接收已被完成,接收缓存不能被再使用时,一个激活的接收请求将不被释放。(给用户的建议结束)。
例如 3.11 使用MPI_REQUEST_FREE的一个例子。
CALL MPI_COMM_RANK(MPI_COMM_WORLD, rank)
IF(rank.EQ.0) THEN
DO i=1, n
CALL MPI_ISEND(outval, 1, MPI_real, 1, 0, req, ierr)
CALL MPI_REQUEST_FREE(req, ierr)
CALL MPI_IRECV(inval, 1, MPI_REAL, 1, 0, req, ierr)
CALL MPI_WAIT(req, status, ierr)
END DO
ELSE ! rank.EQ.1
CALL MPI_IRECV(inva, 1, MPI_REAL, 0, 0, req, ierr)
CALL MPI_WAIT(req, status)
DO I=1, n-1
CALL MPI_ISEND(outval, 1, MPI_REAL, 0, 0, req, ierr)
CALL MPI_REQUEST_FREE(req, ierr)
CALL MPI_IRECV(inval, 1, MPI_REAL, 0, 0, req, ierr)
CALL MPI_WAIT(req, status, ierr)
END DO
CALL MPI_ISEND(outval, 1, MPI_REAL, 0, 0, req, ierr)
CALL MPI_WAIT(req, status)
END IF
Copyright: NPACT |