点对点(p2p)交换
- 两点交换只涉及两个过程,一个是发送者,一个是接收者(消息源和目的地)。
- 两点交换用于本地和非结构化的通信。
- 两点通信只可能在属于同一通信区域的进程之间进行(一个通信器)。
成功的点对点互动的条件
- 发件人必须给出正确的收件人等级
- 收件人必须给出正确的发件人等级
- 同一个交流者
- 标签必须相互匹配
- 接收过程必须有足够的缓冲区大小
两点交换的种类
- 阻断发送/接收,在接收或传输信息时暂停进程。
- 非阻塞式接收/发送,进程继续在后台运行,软件可以在适当的时候要求确认消息已经收到。
点对点(p2p)交换
- 正确组织的两点信息传递必须排除并行MPI-程序的锁定或不正确工作的可能性。
- 两点交换中的错误实例
- 传送了信息但没有收到。
- 源进程和目的进程同时试图阻止消息传递或接收。
点对点(p2p)交换代码
- MPI对两点交换子程序有如下命名惯例:
- MPI_[I][R, S, B]Send
- 这里的前缀[I](立即)表示非阻塞模式。
- 前缀[R, S, B]之一表示就绪、同步和缓冲的交换模式。
- 没有前缀表示是标准交换子程序。
- 有8种类型的信息传递操作。
- 用于接收子程序:
- MPI_[I]Recv
- 即只有2个品种的接待。
- 例如,MPI_Irsend子程序在非阻塞模式下执行 "就绪 "传输,MPI_Bsend以阻塞方式进行缓冲传输,而MPI_Recv则执行阻塞式接收消息。
任何类型的接收子程序都可以接收来自任何发送子程序的信息。
标准锁定装置
int MPI_Send(void *buf, int count, MPI_Datatype datatype,int dest, int tag, MPI_Comm comm)
MPI_Send(buf, count, datatype, dest, tag, comm, ierr)
- buf - 发送缓冲区中第一个元素的地址。
- count - 发送缓冲区中的元素数量(count = 0是允许的)。
- datatype - 每个转发元素的MPI类型。
- dest - 是消息目的进程等级(0和n - 1之间的整数,其中n是通信范围内的进程数)。
- tag - 信息标签。
- comm - 沟通者。
- ierr - 终止代码。
- 在标准的阻塞式转移中,参数列表中使用的任何变量都可以在调用结束后(从转移函数/程序返回后)使用。这种使用不会影响交换的正确性。
- 消息的进一步 "命运 "取决于MPI的实现。消息可以立即传输给接收进程,也可以复制到传输缓冲区。
- 结束通话并不能保证信息已经送达目的地。
标准阻断技术
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)
MPI_Recv(buf, count, datatype, dest, tag, comm, status, ierr)
- buf - 是接收缓冲区中第一个元素的地址。
- count - 接收缓冲区中的元素数量。
- datatype - 每个转发项目的MPI类型。
- source - 发送消息的进程的等级(0和n - 1之间的整数,其中n是通信区域内的进程数)。
- tag - 信息标签。
- comm - 沟通者。
- status - 交易所的状态。
- ierr - 终止代码。
- count的值可能大于收到的信息中的项目数。在这种情况下,只有缓冲区中与实际收到的信息元素相对应的那些元素会在接收完成后被改变。
- MPI_Recv函数保证在调用完成后,消息被接收并放置在接收缓冲区。
信息接收
- 如果一个进程依次向另一个进程发送对应于同一个MPI_Recv调用的两个消息,那么首先发送的消息将被接收。
- 如果两个消息由不同的进程同时发送,它们被接收进程接收的顺序就不是预先确定的了。
代码
- MPI_ERR_COMM - 没有正确指定通讯器。通常在使用 "空 "通信器时发生。
- MPI_ERR_COUNT - count参数的值不正确(要发送的值的数量)。
- MPI_ERR_TYPE - 数据类型参数的错误值。
- MPI_ERR_TAG - 消息标签不正确。
- MPI_ERR_RANK - 消息的来源或目的地等级不正确。
- MPI_ERR_ARG - 不正确的参数,错误的赋值不属于任何错误类别。
- MPI_ERR_REQUEST - 操作请求不正确。
Jokers
- Jokers可以被用作信息源等级和信息标签。
- MPI_ANY_SOURCE - 任何来源。
- MPI_ANY_TAG - 任何标签。
- 当使用 "Jokers "时,有可能会收到不是为这个过程准备的信息。
两点式交流
-
MPI_Recv子程序可以接收以任何模式发送的消息。
- 接收可以从一个任意的进程中进行,在发送操作中必须指定一个相当具体的地址。
- 接收方可以使用 "Jokers "来表示源和标签。进程也可以向自己发送消息,但要注意在这种情况下使用阻塞性操作会导致 "死锁"。
- 收到的信息的大小(计数)可以通过调用子程序确定
- int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count)
- MPI_Get_count(status, datatype, count, ierr)
- count - 传输缓冲区中的元素数量。
- datatype - 每个传输元素的MPI类型。
- status - 交易所的状态。
- ierr - 终止代码。
- 数据类型参数必须与交换操作中指定的数据类型相匹配。
有缓冲的两点交换
-
无论是否登记了相应的接收,都可以启动一个缓冲信息传输。消息源将信息复制到缓冲区,然后以非缓冲模式传输,就像在标准模式下一样。
-
这种操作是本地的,因为它不依赖于相应接收的存在。
-
如果缓冲区大小不够,就会发生错误。缓冲区的分配和大小是由程序员控制的。
- 缓冲区大小必须超过消息大小的MPI_BSEND_OVERHEAD值。这个额外的空间被缓冲的交换子程序用于它自己的目的。
- 如果在执行缓冲交换操作之前没有分配缓冲区,MPI的行为就像一个零大小的缓冲区与进程有关。有这样一个缓冲区的操作通常会以程序崩溃而告终。
- 在程序员需要对内存分配进行更多控制的情况下,建议使用缓冲式交换。这种模式对调试也很方便,因为缓冲区溢出的原因比死锁的原因更容易确定。
- 在进行缓冲交换时,程序员必须事先创建一个足够大的缓冲区。
- int MPI_Buffer_attach(void *buf, size)
- MPI_Buffer_attach(buf, size, ierr)
- 该调用创建了一个大小为字节的缓冲区buf。在Fortran程序中,缓冲区的作用可以是一个数组。一次只能有一个缓冲区连接到一个进程。
- 缓冲传输立即终止,因为信息立即被复制到缓冲区,以便后续传输。
- int MPI_Bsend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)
- MPI_Bsend(buf, count, datatype, dest, tag, comm, ierr)
- 缓冲区完成后,必须停用缓冲区。
- int MPI_Buffer_detach(void *buf, int *size)
- MPI_Buffer_detach(buf, size, ierr)
- 返回将被禁用的缓冲区的地址(buf)和大小(size)。这个操作会阻塞进程,直到缓冲区内的所有信息都被处理。对这个子程序的调用可以用来强制传输信息。调用完成后,缓冲区占用的内存可以再次被使用。在C语言中,这个调用不会自动释放分配给缓冲区的内存。
#include <mpi.h>
#include <stdio.h>
#define M 10
int main( int argc, char **argv )
{
int n;
int rank, size;
MPI_Status status;
MPI_Init( &argc, &argv );
MPI_Comm_size( MPI_COMM_WORLD, &size );
MPI_Comm_rank( MPI_COMM_WORLD, &rank );
if ( rank == 0 ) {
int blen = M * (sizeof(int) + MPI_BSEND_OVERHEAD);
int *buf = (int*) malloc(blen);
MPI_Buffer_attach (buf, blen);
for(int i = 0; i < M; i ++) {
n = i;
MPI_Bsend (&n, 1, MPI_INT, 1, i, MPI_COMM_WORLD );
}
MPI_Buffer_detach(&buf, &blen);
free(buf);
}
else if ( rank == 1) {
for(int i = 0; i < M; i ++) {
MPI_Recv (&n, 1, MPI_INT, 0, i,
MPI_COMM_WORLD,&status );
}
}
MPI_Finalize();
return 0;
}
未完待续~