Дескрипторы производных типов данных могут быть переданы в коммуникационный вызов, где бы ни потребовался аргумент типа данных. Вызов вида MPI_SEND (buf, count, datatype , ...), где count > 1, интерпретируется как если бы вызов был передан новому типу данных, который является конкатенацией некоторого числа копий типа данных. Поэтому MPI_SEND (buf, count, datatype, dest, tag, comm) эквивалентен:
MPI_TYPE_CONTIGUOUS(count, datatype, newtype)
MPI_TYPE_COMMIT(newtype)
MPI_SEND(buf, 1, newtype, dest, tag, comm).
Аналогичное утверждение применимо ко всем коммуникационным функциям, которые имеют аргументы count и datatype.
Предположим, что выполнена операция передачи MPI_SEND(buf,
count, datatype, dest,
tag, comm), где тип задается картой:
{(type0, disp0),...,(typen-1, dispn-1)},
и экстентом extent. (Пустые элементы ``псевдотипа'' MPI_UB и MPI_LB не указаны в карте типа, но они влияют на значение extent). Операция передачи посылает элементов, где элемент находится в ячейке с адресом addr= buf + extent i + disp и имеет тип type, for i = 0 ,..., count-1 and j = 0 ,..., n-1. Эти элементы не обязаны быть ни смежными, ни различными; их порядок может быть произвольным.
Переменная, хранимая по адресу addr в вызывающей подпрограмме должна иметь тип, соответствующий type, где типовое соответствие определяется как в разделе 3.3.1. Посланное сообщение содержит n count элементов, где элемент i n +j имеет тип type.
Аналогично предположим, что выполнена операция приема MPI_RECV (buf, count, datatype, source, tag, comm, status), где тип данных имеет карту
{(type0, disp0) ,...,(typen-1, dispn-1) },
с экстентом extent. (Опять пустые элементы ``псевдотипа'' не указываются в списке карты, но они влияют на значение extent). Эта операция принимает n countэлементов, где элемент i n + j есть в ячейке buf + extent i + disp и имеет тип type. Если входящее сообщение состоит из k элементов, тогда мы обязаны иметь k<=ncount; элемент i n + j должен иметь тип, соответствующий type.
Соответствие типа определяется согласно типу сигнатуры соответствующих типов данных, то есть последовательностью компонент базисного типа данных. Соответствие типов не зависит от некоторых аспектов определения типа данных, таких как смещение (расположение в памяти) или использованных промежуточных типов.
Пример 3.28 Этот пример показывает, что типовое соответствие определяется в терминах базисного типа, из которого состоит производный тип.
...
CALL MPI_TYPE_CONTIGUOUS(2, MPI_REAL, type2, ...)
CALL MPI_TYPE_CONTIGUOUS(4, MPI_REAL, type4, ...)
CALL MPI_TYPE_CONTIGUOUS(2, type2, type22, ...)
...
CALL MPI_SEND(a, 4, MPI_REAL, ...)
CALL MPI_SEND(a, 2, type2, ...)
CALL MPI_SEND(a, 1, type22, ...)
CALL MPI_SEND(a, 1, type4, ...)
...
CALL MPI_RECV(a, 4, MPI_REAL, ...)
CALL MPI_RECV(a, 2, type2, ...)
CALL MPI_RECV(a, 1, type22, ...)
CALL MPI_RECV(a, 1, type4, ...)
Каждая из этих передач соответствует любой операции приема.
Тип данных может описывать перекрывающиеся элементы. Использование такого типа в операциях приема неверно. (Это неверно, даже если полученное сообщение достаточно короткое, чтобы не записывать любой элемент более, чем однажды).
Предположим, что выполнена операция MPI_RECV (buf, count, datatype, dest, tag, comm, status), где тип данных таков
{(type0, disp0) ,...,(typen-1, dispn-1).
Принятое сообщение не обязано ни заполнять весь буфер, ни заполнять число ячеек, которое кратно n. Может быть принято любое число k базисных элементов, где 0 k count n. Количество полученных базисных элементов может быть получено из статуса с помощью функции MPI_GET_ELEMENTS.
Синтаксис функции MPI_GET_ELEMENTS представлен ниже.
MPI_GET_ELEMENTS(status, datatype, count)
IN | status | возвращает статус операции приема (статус) | |
IN | datatype | тип данных операции приема (дескриптор) | |
OUT | count | число принятых базисных элементов (целое) |
int MPI_Get_elements(MPI_Status *status, MPI_Datatype datatype, int *count)
MPI_GET_ELEMENTS(STATUS, DATATYPE, COUNT, IERROR)
INTEGER STATUS(MPI_STATUS_SIZE), DATATYPE, COUNT, IERROR
int MPI::Status::Get_elements(const MPI::Datatype& datatype) const
Ранее определенная функция MPI_GET_COUNT (раздел 3.2.5) имеет различное поведение. Она возвращает количество полученных ``элементов верхнего уровня'', то есть количество ``копий'' типа данных. В предыдущем примере MPI_GET_COUNT может возвратить любое целое число k, где 0 k count n. Если MPI_GET_COUNT возвращает k, тогда число принятых базисных элементов (и значение, возвращенное MPI_GET_ELEMENTS) есть n k. Если число полученных базисных элементов не кратно n, то есть операция приема не получила общее число ``копий'' datatype, то MPI_GET_COUNT возвращает значение MPI_UNDEFINED.
Пример 3.29 Использование MPI_GET_COUNT и MPI_GET_ELEMENT
...
CALL MPI_TYPE_CONTIGUOUS(2, MPI_REAL, Type2, ierr)
CALL MPI_TYPE_COMMIT(Type2, ierr)
...
CALL MPI_COMM_RANK(comm, rank, ierr)
IF(rank.EQ.0) THEN
CALL MPI_SEND(a, 2, MPI_REAL, 1, 0, comm, ierr)
CALL MPI_SEND(a, 3, MPI_REAL, 1, 0, comm, ierr)
ELSE
CALL MPI_RECV(a, 2, Type2, 0, 0, comm, stat, ierr)
CALL MPI_GET_COUNT(stat, Type2, i, ierr) ! возвращает i=1
CALL MPI_GET_ELEMENTS(stat, Type2, i, ierr) ! возвращает i=2
CALL MPI_RECV(a, 2, Type2, 0, 0, comm, stat, ierr)
CALL MPI_GET_COUNT(stat,Type2,i,ierr) ! возвращает
! i=MPI_UNDEFINED
CALL MPI_GET_ELEMENTS(stat, Type2, i, ierr) ! возвращает i=3
END IF
Функция MPI_GET_ELEMENTS также может использоваться после операции probe, чтобы найти число элементов в опробованном сообщении. Заметим, что две функции MPI_GET_COUNT и MPI_GET_ELEMENTS возвращают то же самое значение, когда они используются с базисным типом данных.
Объяснение: Расширение, данное в определении MPI_GET_COUNT, представляется естественным: хотелось бы, чтобы эта функция возвращала значение аргумента count, когда приемный буфер полон. Иногда datatype представляет базисную единицу данных, которую желательно передать, например, запись в массиве записей (структур). Хотелось бы обладать возможностью выяснять, как много компонентов было получено, без забот о разделении числа элементов в каждом компоненте. Однако в другом случае тип данных используется для определения комплексного размещения данных в приемной памяти и не представляет базисную единицу данных для передачи. В таких случаях необходимо использовать функцию MPI_GET_ELEMENTS. []
Совет пользователям: Определение MPI требует, чтобы прием не изменял памяти вне элементов, определенных в качестве составляющих буфера. В частности, определение говорит, что заполненное пространство в структуре не может модифицироваться, когда такая структура скопирована из одного процесса в другой. Это ограничивало бы очевидную оптимизацию копирования структуры вместе с заполнением как один непрерывный блок. Реализация MPI свободна делать такую оптимизацию, если она не воздействует на результат вычислений. Пользователь может ``создать'' эту оптимизацию явным включением заполнения как части сообщения.[]