[3.2] 深入了解recv参数列表里的status
文章目录
- MPI Status & Probe动态的接收
- 1 MPI_Status结构体查询的范例
- 2 use MPI_Probe找出消息大小
MPI Status & Probe动态的接收
MPI_Recv
将MPI_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为什么是阻塞通信。