Ответ 1
MPI предназначен для работы с массивами структур, а не со структурами массивов.
MPI_Hindexed
, который предлагал @suszterpatt, - ужасный взлом. Он позволит вам отправлять только один элемент типа структуры и только элемент, который использовался для определения типа данных MPI. Для других переменных одного и того же типа структуры в большинстве случаев гарантируется, что вычисленные смещения будут ошибочными. Кроме того, типы Hindexed используют один и тот же тип данных MPI для всех элементов и, таким образом, не позволяют отправлять как ints, так и double.
Мудрое дело - превратить вашу программу в использование массивов структур:
typedef struct
{
int i;
double z;
} point;
typedef struct
{
point *A;
int nz;
} column;
Теперь вы можете создать структурированный тип MPI point_type
и использовать его для отправки nz
элементов этого типа, давая column.A
в качестве адреса буфера:
int lens[3];
MPI_Aint base, disps[2];
MPI_Datatype oldtypes[2], point_struct, point_type;
MPI_Get_address(&point, disps);
MPI_Get_address(&point.z, disps+1);
base = disps[0];
lens[0] = 1; disps[0] = MPI_Aint_diff(disps[0], base); oldtypes[0] = MPI_INT;
lens[1] = 1; disps[1] = MPI_Aint_diff(disps[1], base); oldtypes[1] = MPI_DOUBLE;
MPI_Type_create_struct(2, lens, disps, oldtypes, &point_struct);
MPI_Type_create_resized(point_struct, 0, sizeof(point), &point_type);
MPI_Type_commit(&point_type);
MPI_Send(column.A, column.nz, point_type, ...);
Сначала создается тип данных MPI point_struct
, который описывает компоновку элементов структуры, но не учитывает какие-либо дополнения в конце и, следовательно, не может использоваться для надежной отправки массива таких структур. Следовательно, второй тип данных point_type
с правильной степенью создается с помощью MPI_Type_create_resized
.
На стороне приемника вы заглянете в сообщение с помощью MPI_Probe
, извлеките количество элементов с помощью MPI_Get_count
с типом point_type
(который идет прямо в поле nz
), выделите A
и используйте его в MPI_Recv
для получения элементов nz
:
MPI_Status status;
MPI_Probe(source, tag, comm, &status);
MPI_Get_count(&status, point_type, &column.nz);
if (nz == MPI_UNDEFINED)
... non-integral message was received, do something
column.A = (point *)malloc(column.nz*sizeof(point));
MPI_Recv(column.A, column.nz, point_type, source, tag, comm, MPI_STATUS_IGNORE);
Если это изменение кода невозможно, вы все равно можете пройти промежуточный шаг преобразования своей структуры перед отправкой, процесс, обычно называемый (un-) маршалинг. В вашем случае сделайте что-то вроде этого (я предполагаю, что вы храните количество элементов массива в Ai
и Ax
в поле nz
):
point *temp = (point *)malloc(nz*sizeof(point));
for (int i = 0; i < column.nz; i++)
{
temp[i].i = column.Ai[i];
temp[i].z = column.Az[i];
}
MPI_Send(temp, nz, point_type, ...);
free(temp);
На стороне приемника вы должны сделать противоположное: выделить достаточно большой буфер, который может удерживать структуру, получать сообщение в ней и затем делать противоположное преобразование.
И снова вам не нужно передавать фактическое значение nz
, так как его можно легко извлечь из длины сообщения, используя MPI_Get_count
.