Параллельное программирование: Учебное пособие, страница 124

status %s\n", myrank, indata.a,

indata.b, indata.n,

status.MPI_ERROR);

}

MPI_Type_free(&NEW_MESSAGE_TYPE);

MPI_Finalize();

return 0;

}

Здесь сначала задаются типы членов производного типа, а затем количество элементов каждого типа. После этого вычисляются адреса членов типа indata и определяются смещения трех членов производного типа относительно адреса первого, для которого смещение равно 0. Располагая этой информацией, можно определить производный тип, что и делается с помощью подпрограмм MPI_Type_struct и MPI_Type_commit. Созданный таким образом производный тип можно применять в любых операциях обмена.

6.6  Операции упаковки и распаковки данных

Альтернативным методом группировки данных по отношению к созданию производных типов можно считать использование подпрограмм упаковки и распаковки: MPI_Pack и MPI_Unpack. Подпрограмма MPI_Pack позволяет явным образом хранить произвольные (в том числе и расположенные не в последовательных ячейках) данные в непрерывной области памяти (буфере передачи). Подпрограмму MPI_Unpack можно использовать для копирования данных из непрерывного буфера после их приема в произвольные (в том числе и не расположенные непрерывно) ячейки памяти.

Эти подпрограммы используются для обеспечения совместимости с другими библиотеками обмена сообщениями, для приема сообщений по частям, а также для того, чтобы буферизовать исходящие сообщения в пользовательское пространство памяти, что дает независимость от системной политики буферизации.

Следует учесть также, что сообщения передаются по коммуникационной сети, связывающей узлы вычислительной системы. Сеть эта работает довольно медленно, поэтому, чем меньше в параллельной программе обменов, тем меньше потери на пересылку данных. С учетом этого желательно иметь механизм, который позволял бы, например, вместо отправки трех разных значений тремя сообщениями, отправлять их все вместе. Такие механизмы есть — в MPI их три. Это параметр count в подпрограммах обмена, производные типы данных и подпрограммы  MPI_Pack  и  MPI_Unpack.

С помощью аргумента count в подпрограммах MPI_Send, MPI_Receive, MPI_Bcast и MPI_Reduce можно отправить в одном сообщении несколько однотипных элементов данных. Для этого элементы данных должны находиться в непрерывно расположенных ячейках памяти.

Ну, а если элементы данных — это простые переменные? Тогда они могут и не находиться в последовательных ячейках памяти. В этом случае можно использовать производные типы данных или упаковку.

Подпрограмма упаковки может вызываться несколько раз перед передачей сообщения, содержащего упакованные данные, а подпрограмма распаковки в этом случае также будет вызываться несколько раз после выполнения приема. Для извлечения каждой порции данных применяется новый вызов. При распаковке данных текущее положение указателя в буфере сохраняется.

Интерфейс подпрограммы MPI_Pack выглядит следующим образом:

int MPI_Pack(void *inbuf, int incount,

MPI_Datatype datatype, void *outbuf,

int outcount, int *position,

MPI_Comm comm)

При вызове incount элементов указанного типа выбираются из входного буфера и упаковываются в выходном буфере, начиная с положения position.

Входные параметры:

·  inbuf — начальный адрес входного буфера;

·  incount — количество входных данных;

·  datatype — тип каждого входного элемента данных;

·  outcount — размер выходного буфера в байтах;

·  position — текущее положение в буфере в байтах;

·  comm — коммуникатор для упакованного сообщения.

Выходной параметр outbuf является стартовым адресом выходного буфера.

Обратным действием обладает подпрограмма MPI_Unpack, которая используется для распаковки данных:

int MPI_Unpack(void *inbuf, int insize,

int *position, void *outbuf, int outcount,

MPI_Datatype datatype, MPI_Comm comm)

Входные параметры:

·  inbuf — стартовый адрес входного буфера;

·  insize — размер входного буфера в байтах;

·  position — текущее положение в байтах;

·  outcount — количество данных, которые нужно распаковать;