MPICH笔记(二):阻塞通信

MPICH笔记(二):阻塞通信

MPICH支持点对点通信,主要使用:

MPI_Send()MPI_Recv(),两个函数一个是发送,一个是接收,官方的文档十分详细,单击前边的这两个函数即可跳转到对应页面。

需要注意的是:MPI_Recv()是阻塞接收函数,保证在接收到消息前不会执行之后的语句;然而,根据文档的描述,MPI_Send()是阻塞发送函数,但是却可能会不发生阻塞,也就是说,函数可能在发送的消息被确认接收前返回。

另一点需要注意的是,因为MPI_Recv()会进行阻塞,所以需要考虑避免死锁现象,即同一时间所有的进程都进行MPI_Recv()操作。如下面的代码将0号进程设置为先发送再接收,而其它进程都是先接收,再发送消息,这样来避免死锁。

代码:

#include <iostream>
#include "mpi.h"

using namespace std;

int main(void) {
    int rank, size;
    int message;
    int from, to;
    MPI_Init(nullptr, nullptr);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    from = ((rank - 1) % size + size) % size;
    to = (rank + 1) % size;
    if (rank) {
        MPI_Recv(&message, 1, MPI_INT, from, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        printf("Rank %d > Hello from %d, and the message is %d\n", rank, from, message);
        MPI_Send(&rank, 1, MPI_INT, to, 0, MPI_COMM_WORLD);
    } else {
        MPI_Send(&rank, 1, MPI_INT, to, 0, MPI_COMM_WORLD);
        MPI_Recv(&message, 1, MPI_INT, from, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
        printf("Rank %d > Hello from %d, and the message is %d\n", rank, from, message);
    }
    MPI_Finalize();
    return 0;
}

 

输出:

Rank 1 > Hello from 0, and the message is 0
Rank 2 > Hello from 1, and the message is 1
Rank 3 > Hello from 2, and the message is 2
Rank 4 > Hello from 3, and the message is 3
Rank 5 > Hello from 4, and the message is 4
Rank 6 > Hello from 5, and the message is 5
Rank 7 > Hello from 6, and the message is 6
Rank 0 > Hello from 7, and the message is 7

注:这里一共开启了8个进程。

 

代码概述:

int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

前三个参数是表述消息信息的三元组,依此是存储位置、数量(在接收函数中,这个参数表示最大可能的数据长度,需要保证这个大小要不小于实际传递信息的小才可以成功接收数据)、单位大小(数据类型)。source是来源进程的rank,如果不限定来源,可以使用预定义量MPI_ANY_SOURCE。tag表示消息的编号,因为可能有多个来自同一进程的不同作用的信息,如果不限制tag值,可以使用预定义常量MPI_ANY_TAG。status参数是用来获取消息的状态信息,如果不需要关于此消息的状态信息,可以使用预定义常量MPI_STATUS_IGNORE。

关于MPI_Status的详情见:https://docs.microsoft.com/en-us/message-passing-interface/mpi-status-structure

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

前三个参数仍然是描述信息的三元组,其中count需要是传输信息的实际数量。而后dest是接收进程在comm通信子内的rank。tag要与接收者设置的tag一致,注意,不可以使用MPI_ANY_TAG。

注:关于阻塞,两个阻塞式通信函数都会一直阻塞直到内存申请成功,关于具体细节,此处占坑,日后补充。