[3.2] 深入了解recv参数列表里的status

MPI Status & Probe动态的接收

MPI_RecvMPI_Status结构体的地址作为参数,可以使用MPI_STATUS_IGNORE 忽略。如果我们将 MPI_Status 结构体传递给 MPI_Recv 函数,则操作完成后将在该结构体中填充有关接收操作的其他信息。 三个主要的信息包括:

  • 发送端的rank,发送端的rank存储在结构体MPI_SOURCE元素中,如果声明一个MPI_Status state对象,则可以通过state.MPI_SOURCE访问rank。

    typedef struct MPI_Status {
        int count_lo;                  // 低位的计数值,表示接收到的数据量的低32位(可能与 count_hi_and_cancelled 组合成完整的 64 位计数)
        int count_hi_and_cancelled;    // 高位的计数值(如果存在高32位),同时包含一个“取消标志”位
        int MPI_SOURCE;                // 消息的源进程的 rank(表示接收消息是从哪个进程来的)
        int MPI_TAG;                   // 消息的标签(与发送时指定的标签对应,用于标识消息的类型)
        int MPI_ERROR;                 // 错误码(用于存储接收操作的返回状态,MPI_SUCCESS 表示成功)
    } MPI_Status;
    
  • 消息的标签,同上访问方式,访问MPI_TAG

  • 消息的长度,它在在结构体中没有预定义的元素。我们必须使用 MPI_Get_count 找出消息的长度。

    MPI_Get_count(const MPI_Status *status, MPI_Datatype datatype, int *count)
    

    MPI_Get_count中需要传递 MPI_Status 结构体,消息的 datatype(数据类型),并返回 count。 变量 count 是已接收的 datatype 元素的数目。

1 MPI_Status结构体查询的范例

// mpicc mpi_status.cc -o mpi_status
// mpirun -np 2 ./mpi_status
#include <mpi.h>
#include <iostream>
#include <stdio.h>

int main(int argc, char** argv) {
    MPI_Init(NULL, NULL);
  
    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size);
    if (world_size != 2) {
      fprintf(stderr, "Must use two processes for this example\n");
      MPI_Abort(MPI_COMM_WORLD, 1);
    }
    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
  
    const int MAX_NUMBERS = 100;
    int numbers[MAX_NUMBERS];
    int number_amount;
    if (world_rank == 0) {
      // Pick a random amount of integers to send to process one
      srand(time(NULL));
      number_amount = (rand() / (float)RAND_MAX) * MAX_NUMBERS;
      // Send the amount of integers to process one
      MPI_Send(numbers, number_amount, MPI_INT, 1, 0, MPI_COMM_WORLD);
      printf("0 sent %d numbers to 1\n", number_amount);
    } else if (world_rank == 1) {
      MPI_Status status;
      // Receive at most MAX_NUMBERS from process zero
      MPI_Recv(numbers, MAX_NUMBERS, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
      // After receiving the message, check the status to determine how many
      // numbers were actually received
      MPI_Get_count(&status, MPI_INT, &number_amount);
      // Print off the amount of numbers, and also print additional information
      // in the status object
      printf("1 received %d numbers from 0. Message source = %d, tag = %d\n",
             number_amount, status.MPI_SOURCE, status.MPI_TAG);
    }
    MPI_Barrier(MPI_COMM_WORLD);
    MPI_Finalize();
    return 0;
}
/******************************************************************
0 sent 91 numbers to 1
0 sent 91 numbers to 1
*******************************************************************/

2 use MPI_Probe找出消息大小

在库文件中的定义如下,可以看到与MPI_Recv很类似。可以使用 MPI_Probe 在实际接收消息之前查询消息大小。除了不接收消息之外,MPI_Probe会阻塞具有匹配标签和发送端的消息。消息可用时,会填充Status。然后,用户可以使用 MPI_Recv 接收实际的消息。

MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status)
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main (int argc, char** argv) {
    MPI_Init(NULL, NULL);

    int world_size;
    MPI_Comm_size(MPI_COMM_WORLD, &world_size); // Get the number of processes
    if (world_size != 2) {
        fprintf(stderr, "Error: This program requires exactly 2 processes.\n");
        MPI_Abort(MPI_COMM_WORLD, 1);
    }

    int world_rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &world_rank); // Get the rank of the current process

    int number_of_amount = 0;
    if (world_rank == 0) {
        int MAX_NUMBERS = 100;
        int numbers[MAX_NUMBERS];
        srand(time(NULL));
        number_of_amount = (rand() / (float)RAND_MAX) * MAX_NUMBERS;
        MPI_Send(numbers, number_of_amount, MPI_INT, 1, 0, MPI_COMM_WORLD);
        printf("Process %d sent %d numbers to process %d.\n", world_rank, number_of_amount, 1);
    } else if (world_rank == 1) {
        MPI_Status status;
        MPI_Probe(0, 0, MPI_COMM_WORLD, &status);
        MPI_Get_count(&status, MPI_INT, &number_of_amount);
        int* number_buffer = (int*)malloc(sizeof(int) * number_of_amount);
        MPI_Recv(number_buffer, number_of_amount, MPI_INT, 0, 0, MPI_COMM_WORLD,
            MPI_STATUS_IGNORE);
            printf("1 dynamically received %d numbers from 0.\n",
                number_of_amount);
        free(number_buffer);
    }
    MPI_Finalize();
}
/******************************************************************
Process 0 sent 29 numbers to process 1.
1 dynamically received 29 numbers from 0.
*******************************************************************/

MPI_Probe 构成了许多动态 MPI 应用程序的基础。 例如,控制端/执行子程序在交换变量大小的消息时通常会大量使用 MPI_Probe。 作为练习,对 MPI_Recv 进行包装,将 MPI_Probe 用于您可能编写的任何动态应用程序。 它将使代码看起来更美好:-)
下一节将通过完整的代码例子说明send和recv为什么是阻塞通信。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小马敲马

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值