MPI_Type_create_subarray()
并不接收原始数组,也不返回子数组;它创建一个MPI类型,描述给定类型的大数组中子数组的存储布局,需要提供一组子数组大小和一个起始点。
您可以使用这个新创建的MPI类型从任何适当大小的数组中提取所需的数据,并将其发送到另一个任务(通过点对点消息传递例程)、所有其他任务(通过集合传递),或将其写入磁盘(使用MPI-IO)。在下面的示例中,rank 0 使用一个MPI子数组类型从一个整数的大数组中提取一个子数组,并将其发送到rank 1。 接收到这个数据的rank 1 只需将其作为若干个整数接收,而无需特别地接收它。
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
void printarr(int **data, int n, char *str);
int **allocarray(int n);
int main(int argc, char **argv) {
const int bigsize =10;
const int subsize =5;
const int sender =0;
const int receiver=1;
const int ourtag =2;
int rank, size;
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (size < receiver+1) {
if (rank == 0)
fprintf(stderr,"%s: Needs at least %d processors.\n", argv[0], receiver+1);
MPI_Finalize();
return 1;
}
if (rank == sender) {
int **bigarray = allocarray(bigsize);
for (int i=0; i<bigsize; i++)
for (int j=0; j<bigsize; j++)
bigarray[i][j] = i*bigsize+j;
printarr(bigarray, bigsize, " Sender: Big array ");
MPI_Datatype mysubarray;
int starts[2] = {5,3};
int subsizes[2] = {subsize,subsize};
int bigsizes[2] = {bigsize, bigsize};
MPI_Type_create_subarray(2, bigsizes, subsizes, starts,
MPI_ORDER_C, MPI_INT, &mysubarray);
MPI_Type_commit(&mysubarray);
MPI_Send(&(bigarray[0][0]), 1, mysubarray, receiver, ourtag, MPI_COMM_WORLD);
MPI_Type_free(&mysubarray);
free(bigarray[0]);
free(bigarray);
} else if (rank == receiver) {
int **subarray = allocarray(subsize);
for (int i=0; i<subsize; i++)
for (int j=0; j<subsize; j++)
subarray[i][j] = 0;
MPI_Recv(&(subarray[0][0]), subsize*subsize, MPI_INT, sender, ourtag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
printarr(subarray, subsize, " Receiver: Subarray -- after receive");
free(subarray[0]);
free(subarray);
}
MPI_Finalize();
return 0;
}
void printarr(int **data, int n, char *str) {
printf("-- %s --\n", str);
for (int i=0; i<n; i++) {
for (int j=0; j<n; j++) {
printf("%3d ", data[i][j]);
}
printf("\n");
}
}
int **allocarray(int n) {
int *data = malloc(n*n*sizeof(int));
int **arr = malloc(n*sizeof(int *));
for (int i=0; i<n; i++)
arr[i] = &(data[i*n]);
return arr;
}
运行此命令会得到以下结果
$ mpicc -o subarray subarray.c -std=c99 -Wall -g
$ mpirun -np 2 ./subarray
-- Sender: Big array --
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99
-- Receiver: Subarray -- after receive --
53 54 55 56 57
63 64 65 66 67
73 74 75 76 77
83 84 85 86 87
93 94 95 96 97
MPI_Sendrecv
可以省略掉一些代码。 - Hristo Ilievmpi_type_create_subarray
来发送和接收边界区域/幽灵行。你需要创建子数组类型来描述你要发送给上/下/左/右邻居的“真实”更新数据,并描述你要接收到的幽灵行,然后像上面的示例一样发送和接收它们。但你仍然需要进行发送和接收操作。你创建的子数组类型不会进行任何通信,也不会生成任何指针或其他内容;它只是描述了一个内存布局,使你能够直接将数据发送/接收到你的网格中。 - Jonathan Dursi