Дескрипторы производных типов данных могут быть переданы в коммуникационный вызов, где бы ни потребовался аргумент типа данных. Вызов вида 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<=n
count; элемент 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 свободна делать такую оптимизацию, если она не воздействует на результат вычислений. Пользователь может ``создать'' эту оптимизацию явным включением заполнения как части сообщения.[]