并行算法讲义 联系客服

发布时间 : 星期一 文章并行算法讲义更新完毕开始阅读d6ac36768e9951e79b8927da

+ SOURCE, RECVTAG, COMM, IERR INTEGER STATUS(MPI_STATUS_SIZE)

§3.2 消息发送模式

MPI共有四种模式的消息发送函数,这些函数具有完全一样的入口参数,但它们发送消息的方式或对接收方的状态要求不同。

标准模式 (standard mode): 由 MPI 系统来决定是否将消息拷贝至一个缓冲区然后立即返回 (此时消息的发送由 MPI 系统在后台进行),还是等待将数据发送出去后再返回。大部分 MPI 系统预留了一定大小的缓冲区,当发送的消息长度小于缓冲区大小时会将消息缓冲然后立即返回,否则,当部分或全部消息发送完成后才返回。标准模式发送被称为是非局部的,因为它的完成可能需要与接收方联络。标准模式的阻塞发送函数为 MPI_Send。

缓冲模式 (buffered mode) MPI系统将消息拷贝至一个用户提供的缓冲区然后立即返回,消息的发送由 MPI 系统在后台进行。用户必须确保所提供的缓冲区大小足以容下采用缓冲模式发送的消息。缓冲模式发送操作被称为是局部的,因为它不需要与接收方联络即可立即完成(返回)。 缓冲模式的阻塞发送函数为 MPI_Bsend。

同步模式 (synchronous mode): 实际上就是在标准模式的基础上还要求确认接收方已经开始接收数据后函数调用才返回。显然,同步模式的发送是非局部的。 同步模式的阻塞发送函数为MPI_Ssend。

就绪模式 (ready mode): 调用就绪模式发送时必须确保接收方已经处于就绪状态 (正在等待接收该消息),否则该调用将产生一个错误。该模式设立的目的是在一些以同步方式工作的并行系统上,由于发送时可以假设接收方已经在接收而减少一些消息发送的开销。如果一个使用就绪模式的MPI程序是正确的,则将其中所有就绪模式的消息发送改为标准模式后也应该是正确的。就绪模式的阻塞发送函数为 MPI_ Rsend。

后三种模式的消息发送函数名分别在标准模式消息发送函数 MPI_Send 中加上 B、S 和 R 得到,并且四个函数具有完全一样的参数。 §3.2.1 阻塞型缓冲模式消息发送函数 C

int MPI_Bsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)

Fortran 77

MPI_BSEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, IERR) BUF(*)

INTEGER COUNT, DATATYPE, DEST, TAG, COMM, IERR

提交阻塞型缓冲模式的消息发送,各参数的含义与 MPI_Send相同。该函数将 buf中的数据拷贝到一个用户指定的缓冲区中然后立即返回。实际发送由 MPI 系统在后台进行,用户在调用该函数前必须调用 MPI_Buffer_attach 来为它提供一个发送缓冲区: C

int MPI_Buffer_attach( void* buffer, int size)

Fortran 77

MPI_BUFFER_ATTACH( BUFFER, SIZE, IERR) BUFFER(*) INTEGER SIZE, IERR

将 buffer 提交为供 MPI_Bsend 使用的缓冲区,该缓冲区的长度为size字节。MPI只允许提交一个供 MPI_Bsend 使用的缓冲区,用户应该保证该缓冲区足够容下所有可能同时用 MPI_Bsend 发送的消息 (每个消息所需的缓冲区长度通常等于消息中数据的长度加上一个常量,用户可以调用函数MPI_Type_size 来查询一个消息实际需要的缓冲区长度)。 MPI_Buffer_detach 撤消用 MPI_Buffer_attach 提交的缓冲区。在调用

MPI_Buffer_detach 前,用户不应该修改缓冲区中的内容,以免破坏正在发送的消息。该函数的返回亦表明所有缓冲模式的消息发送均已完成。 C

int MPI_Buffer_detach( void *buffer_addr, int *size)

Fortran 77

MPI_BUFFER_DETACH( BUFFER_ADDR, SIZE, IERR) BUFFER_ADDR(*) INTEGER SIZE, IERR

注意,上述函数中 buffer_addr 和 size 均为输出参数。其中 buffer_addr 返回所撤消的缓冲区的地址,而 size 则返回所撤消的缓冲区长度。 §3.3 阻塞型与非阻塞型函数

阻塞型 (blocking): 阻塞型函数需要等待指定操作的实际完成,或至少所涉及的数据已被 MPI 系统安全地备份后才返回。如 MPI_Send 和 MPI_Recv 都是阻塞型的。MPI_Send 调用返回时表明数据已经发出,或被 MPI系统复制,随后对发送缓冲区的修改不会改变所发送的数据。而 MPI_Recv 返回时,则表明数据接收已经完成。阻塞型函数的操作是非局部的,它的完成可能需要与其它进程 进行通信。阻塞型函数使用不当很容易引起程序的死锁。

非阻塞型 (non_blocking): 非阻塞型函数的调用总是立即返回,而实际操作则由 MPI 系统在后台进行,用户必须随后调用其它函数来等待或查询操作的完成情况。在操作完成之前对相关数据区的操作是不安全的,因为随时可能与正在后台进行的操作发生冲突。非阻塞型函数调用是局部的,因为它的完成不需要与其它进程进行通信。在有些并行系统上,通过非阻塞型函数的使用可以实现计算与通信的重叠进行。 §3.4 非阻塞型点对点通信函数 §3.4.1 非阻塞发送 C

int MPI_Isend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request)

Fortran 77

MPI_ISEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, + REQUEST, IERR)

BUF(*)

INTEGER COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERR

该函数递交一个消息发送请求,要求 MPI 系统在后台完成消息的发送。MPI_Isend 函数为该发送创建一个请求,并将请求的句柄通过 request 变量返回给 MPI进程,供随后查询/等待消息发送的完成用。

与阻塞消息发送一样,非阻塞消息发送也有四种模式: 标准模式 (MPI_Isend) 、 缓冲模式(MPI_Ibsend) 、 同步模式 (MPI_Issend) 和就绪模式 (MPI_Irsend),后三种模式较少使用,我们不在此介绍。 §3.4.2 非阻塞接收 C

int MPI_Irecv(void *buf, int count, MPI_Datatype datatype,

int source, int tag, MPI_Comm comm, MPI_Request *request)

Fortran 77

MPI_IRECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, + REQUEST, IERR) BUF(*)

INTEGER COUNT, DATATYPE, SOURCE, TAG, COMM, REQUEST, + IERR

该函数递交一个消息接收请求,要求 MPI 系统在后台完成消息的接收。MPI_Isend 函数为该接收创建一个请求并将请求的句柄通过 request 变量返回给 MPI进程,供随后查询/等待消息发送的完成用。

22 §3.4.3 通信请求的完成与检测 §3.4.3.1 等待、 检测一个通信器请求的完成 C

int MPI_Wait(MPI_Request *request, MPI_Status status) int MPI_Test(MPI_Request *request, int *flag, MPI_Status status)

Fortran 77

MPI_WAIT(REQUEST, STATUS, IERR)

INTEGER REQUEST, STATUS(MPI_STATUS_SIZE), IERR MPI_TEST(REQUEST, FLAG, STATUS, IERR)

INTEGER REQUEST, STATUS(MPI_STATUS_SIZE), IERR LOGICAL FLAG

MPI_Wait 是阻塞型函数,它必须等待通信的完成才返回。 MPI_Test 是与之相对应的非阻塞函数。

MPI_Wait 等待指定的通信请求完成然后返回。成功返回时,status 中包含关于所完成的通信的信息,相应的通信请求被释放,request 被置成 MPI_REQUEST_NULL.

MPI_Test检测指定的通信请求,不论通信是否完成都立即返回。如果通信已经完成则返

回flag = true, status 中包含关于所完成的通信的信息,相应的通信请求被释放,request 被置成MPI_REQUEST_NULL。 如果通信尚未完成则返回 flag=false。

对于接收请求,status 返回的内容与 MPI_Recv 返回的一样。对于发送请求, status 的返回的值不确定。 §3.4.3.2 等待、 检测一组通信请求中某一个的完成 C

int MPI_Waitany(int count,

MPI_Request *array_of_requests, int *index, MPI_Status status) int MPI_Testany(int count,

MPI_Request *array_of_requests,

int *index, int *flag, MPI_Status status)

Fortran 77

MPI_WAITANY(COUNT, ARRAY_OF_REQUESTS, INDEX, STATUS, + IERR)

INTEGER COUNT, ARRAY_OF_REQUESTS(*), INDEX, IERR INTEGER STATUS(MPI_STATUS_SIZE)

MPI_TESTANY(COUNT, ARRAY_OF_REQUESTS, INDEX, FLAG, + STATUS, IERR)

INTEGER COUNT, ARRAY_OF_REQUESTS(*), INDEX, IERR INTEGER STATUS(MPI_STATUS_SIZE) LOGICAL FLAG

等待或检测 array_of_requests 给出的通信请求中任何一个的完成。成功返回时, index 中包含所完成的通信请求在数组 array_of_requests 中的位置。其它参数的含义与 MPI_Wait和 MPI_Test相同。 §3.4.3.3 等待、 检测一组通信器请求的全部完成 C

int MPI_Waitall(int count,

MPI_Request *array_of_requests, MPI_Status *array_of_statuses) int MPI_Testall(int count,

MPI_Request *array_of_requests,

int *flag, MPI_Status *array_of_statuses)

Fortran 77

MPI_WAITALL(COUNT, ARRAY_OF_REQUESTS, ARRAY_OF_STATUSES, + IERR)

INTEGER COUNT, ARRAY_OF_REQUESTS(*), IERR

INTEGER ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*) MPI_TESTALL(COUNT, ARRAY_OF_REQUESTS, FLAG, + ARRAY_OF_STATUSES, IERR)

INTEGER COUNT, ARRAY_OF_REQUESTS(*), IERR