c - How to use MPI to transfer a custom struct with a dynamic array?
问题描述
There is a simple example to describe my question. I have a custom struct which contains a dynamic array
struct my_data_type {
int c;
int d[];
};
and the root process (process 0) has an array of such struct nums[4]
.
I want to send chunks of the array to different processes (for example, 2 processes) via MPI_Scatter
. The main problem here is that I want this array d[]
to be dynamic.
The main code is the following:
int main(int argc, char* argv[]) {
MPI_Init(NULL, NULL);
int my_size; MPI_Comm_size(MPI_COMM_WORLD, &my_size);
int my_rank; MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
int len = 2; //example: the dynamic array d contains len=2 elements
my_data_type *nums //nums[4]
= (my_data_type*)malloc((sizeof(my_data_type) + sizeof(int) * len) * 4);
my_data_type *sub_nums //sub_nums[2]
= (my_data_type*)malloc((sizeof(my_data_type) + sizeof(int) * len) * 2);
if (my_rank == 0) { //just some examples
nums[0].c = 0; nums[1].c = 1; nums[2].c = 2; nums[3].c = 3;
nums[0].d[0] = 10; nums[1].d[0] = 11; nums[2].d[0] = 12; nums[3].d[0] = 13;
nums[0].d[1] = 14; nums[1].d[1] = 15; nums[2].d[1] = 16; nums[3].d[1] = 17;
}
MPI_Datatype mpi_data_type; //new datatype
int blocklens[2];
MPI_Datatype old_types[2];
MPI_Aint indices[2];
blocklens[0] = 1; blocklens[1] = len;
old_types[0] = MPI_INT; old_types[1] = MPI_INT;
MPI_Address(&nums[0].c, &indices[0]);
MPI_Address(&nums[0].d[0], &indices[1]);
indices[1] = indices[1] - indices[0];
indices[0] = 0;
MPI_Type_create_struct(2, blocklens, indices, old_types, &mpi_data_type);
MPI_Type_commit(&mpi_data_type);
MPI_Scatter(nums, 2, mpi_data_type,
sub_nums, 2, mpi_data_type,
0, MPI_COMM_WORLD);
cout << "rank " << my_rank << ": " << endl;
cout << "c: " << sub_nums[0].c << ", " << sub_nums[1].c << endl;
cout << "d: " << sub_nums[0].d[0] << ", " << sub_nums[0].d[1] << ", ";
cout << sub_nums[1].d[0] << ", " << sub_nums[1].d[1] << endl;
MPI_Finalize();
return 0;
}
If I change the int d[];
into int d[2];
in the definition of struct my_data_type
, I will certainly get the expected results like
rank 0:
c: 0, 1
d: 10, 14, 11, 15
rank 1:
c: 2, 3
d: 12, 16, 13, 17
But if not, the results are the following:
rank 0:
c: 0, 10
d: 10, 14, 14, 15
rank 1:
c: 33, 0
d: 0, 0, 0, 1
As you can see, I know the problem is about the dynamic array, but I cannot use a static one in my project. So how can I change my code above to get the expected results?
解决方案
您的基本问题不是 mpi,而是使用具有灵活数组成员的 struct 数组。这是一个示例程序来说明问题
#include <assert.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct s s;
struct s
{
int c;
int d[];
};
int main(int argc, char* argv[])
{
assert(sizeof(s) == sizeof(int));
int len = 4;
s* okay = malloc(sizeof(*okay) + sizeof(int)*len);
intptr_t true_size = (intptr_t)&okay->d[len] -(intptr_t)(okay);
assert(true_size == ((len+1)*sizeof(int)));
int nbad = 6;
s* bad = malloc((sizeof(*bad) + sizeof(int)*len)*nbad);
intptr_t bad_size = (intptr_t)&bad[1] -(intptr_t)&bad[0];
/* this size mismatch means arrays of `s` do not do what you think they do */
assert(bad_size != true_size);
assert(bad_size == sizeof(int));
assert((char*)&bad[1] == (char*)&bad[0].d[0]);
assert((char*)&bad[2] == (char*)&bad[0].d[1]);
assert((char*)&bad[3] == (char*)&bad[0].d[2]);
assert((char*)&bad[1].d[0] == (char*)&bad[0].d[1]);
assert((char*)&bad[2].d[0] == (char*)&bad[0].d[2]);
assert((char*)&bad[3].d[0] == (char*)&bad[0].d[3]);
}
要处理具有灵活数组成员的结构数组,您需要手动计算用于索引的内存偏移量,而不是依赖编译器。所以你可以像这样定义一个辅助函数:
s* s_index(const s* a, int len, int index)
{
uintptr_t true_size = sizeof(*a) + len*sizeof(int);
return (s*)((char*)a + index * true_size);
}
然后用于s_index
访问所需的数组成员,而不是bad[0]
,bad[1]
构造:
s* first = s_index(bad, len, 0);
s* second = s_index(bad, len, 1);
assert((char*)&first->d[len] == (char *)second);
推荐阅读
- python - Python if 对字符串列表的语句以及对期望/排除关键字列表的任何语句
- spring-boot - @EnableSwagger - 无法在 Spring Boot 中解决
- node.js - 如何从反应客户端应用程序中的输入标签获取文件
- asp.net-mvc - 如何在图像中显示的框中创建图像和文本
- makefile - 为什么此命令在终端中有效,但在 makefile 中无效?
- vimium - Vimium:输入字段的“f”之类的东西?
- c# - 在这种使用 Task.WhenAll 的情况下是否需要 ConcurrentQueue?
- oracle - 如何搜索和过滤“&”符号?
- video-streaming - 在线直播教育场景如何优化x264?
- javascript - 如何更改每个点的弧中使用的strokeStyle?