我正在尝试实施MPI_Bcast,并且我计划通过MPI_Send但MPI_Recv似乎我无法向自己发送消息?
代码如下
void My_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm) {
int comm_rank, comm_size, i;
MPI_Comm_rank(comm, &comm_rank);
MPI_Comm_size(comm, &comm_size);
if(comm_rank==root){
for(i = 0; i < comm_size; i++){
MPI_Send(buffer, count, datatype, i, 0, comm);
}
}
MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE);
}
Run Code Online (Sandbox Code Playgroud)
对此有什么建议吗?或者我不应该向自己发送消息而只是进行内存复制?
你的程序在多个层面上都是错误的。首先,条件语句有一个错误:
if(comm_rank=root){
Run Code Online (Sandbox Code Playgroud)
这不是比较comm_rank而是root分配root给comm_rank,然后循环仅在root非零时才执行,此外它会由所有等级执行。
其次,根进程不需要向自身发送数据,因为数据已经存在。即使您想发送和接收,您也应该注意到两者MPI_Send并MPI_Recv仔细阅读相同的缓冲区空间,这是不正确的。一些 MPI 实现使用直接内存复制进行自交互,即库可能用来memcpy()传输消息。使用memcpy()重叠缓冲区(包括使用相同的缓冲区)会导致未定义的行为。
实现线性广播的正确方法是:
void My_MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm)
{
int comm_rank, comm_size, i;
MPI_Comm_rank(comm, &comm_rank);
MPI_Comm_size(comm, &comm_size);
if (comm_rank == root)
{
for (i = 0; i < comm_size; i++)
{
if (i != comm_rank)
MPI_Send(buffer, count, datatype, i, 0, comm);
}
}
else
MPI_Recv(buffer, count, datatype, root, 0, comm, MPI_STATUS_IGNORE);
}
Run Code Online (Sandbox Code Playgroud)
进程与自身对话而不发生死锁的通常方法是:
MPI_Isend使用和 的组合或和MPI_Recv的组合;MPI_SendMPI_IrecvMPI_Bsend;MPI_Sendrecv或MPI_Sendrecv_replace.在像您这样在循环中完成多个发送的情况下,MPI_Irecv和 的组合效果很好。MPI_Send例如:
MPI_Request req;
// Start a non-blocking receive
MPI_Irecv(buff2, count, datatype, root, 0, comm, &req);
// Send to everyone
for (i = 0; i < comm_size; i++)
MPI_Send(buff1, count, datatype, i, 0, comm);
// Complete the non-blocking receive
MPI_Wait(&req, MPI_STATUS_IGNORE);
Run Code Online (Sandbox Code Playgroud)
请注意发送和接收使用单独的缓冲区。可能唯一允许将同一缓冲区用于发送和接收的点对点 MPI 通信调用以及MPI_Sendrecv_replace集体 MPI 调用的就地模式。但这些是在内部以这样的方式实现的,即同一存储区域不会同时用于发送和接收。