1 1 Коммуникационные операции типа точка-точка

К операциям этого типа относятся две представленные в предыдущем разделе коммуникационные процедуры. В коммуникационных операциях типа точка-точка всегда участвуют не более двух процессов: передающий и принимающий. В MPI имеется множество функций, реализующих такой тип обменов. Многообразие объясняется возможностью организации таких обменов множеством способов. Описанные в предыдущем разделе функции реализуют стандартный режим с блокировкой.

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

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

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

Режимы выполненияС блокировкой Без блокировки
Стандартная посылка MPI_Send MPI_ISend
Синхронная посылка MPI_SSend MPI_ISSend
Буферизованная посылка MPI_BSend MPI_IBSend
Согласованная посылка MPI_RSend MPI_IRsend
Прием информации MPI_Recv MPI_IRecv

Из таблицы хорошо виден принцип формирования имен функций. К именам базовых функций Send/Recv добавляются различные префиксы.

  • Префикс S (synchronous) -
  • означает синхронный режим передачи данных. Операция передачи данных заканчивается только тогда, когда заканчивается прием данных. Функция нелокальная.
  • Префикс B (buffered) -
  • означает буферизованный режим передачи данных. В адресном пространстве передающего процесса с помощью специальной функции создается буфер обмена, который используется в операциях обмена. Операция посылки заканчивается, когда данные помещены в этот буфер. Функция имеет локальный характер.
  • Префикс R (ready) -
  • согласованный или подготовленный режим передачи данных. Операция передачи данных начинается только тогда, когда принимающий процессор выставил признак готовности приема данных, инициировав операцию приема. Функция нелокальная.
  • Префикс I (immediate) -
  • относится к неблокирующим операциям.

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

В стандартном режиме выполнение операции обмена включает три этапа:

  1. Передающая сторона формирует пакет сообщения. Этот пакет передается отправителем в системный буфер, и на этом функция посылки сообщения заканчивается.
  2. Сообщение системными средствами передается адресату.
  3. Принимающий процессор извлекает сообщение из системного буфера, когда у него появится потребность в этих данных. Содержательная часть сообщения помещается в адресное пространство принимающего процесса (параметр buf), а служебная - в параметр status.

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

C определяем свой идентификатор процесса
      CALL MPI_COMM_RANK(comm, rank, ierr)
      IF (rank.EQ.0) THEN
C если это первый процесс, то сначала посылаем данные, ждем завершения операции, потом принимаем
          CALL MPI_SEND(sendbuf, count, MPI_REAL, 1, tag, comm, ierr)
          CALL MPI_RECV(recvbuf, count, MPI_REAL, 1, tag, comm, status, ierr)
      ELSE IF (rank.EQ.1) THEN
C если это второй процесс, то сначала принимаем данные, ждем завершения операции, потом отсылаем
          CALL MPI_RECV(recvbuf, count, MPI_REAL, 0, tag, comm, status, ierr)
	  CALL MPI_SEND(sendbuf, count, MPI_REAL, 0, tag, comm, ierr)
      END IF	 

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

    MPI_SENDRECV(SENDBUF, SENDCOUNT, SENDTYPE, DEST, SENDTAG, RECVBUF,
 	         RECVCOUNT, RECVTYPE, SOURCE, RECVTAG, COMM, STATUS, IERROR)
    <type> SENDBUF(*), RECVBUF(*)
    INTEGER SENDCOUNT, SENDTYPE, DEST, SENDTAG, RECVCOUNT, RECVTYPE,
            SOURCE, RECV TAG, COMM, STATUS(MPI_STATUS_SIZE), IERROR
ТипПараметрОписание
INsendbufадрес начала расположения посылаемого сообщения
INsendcountчисло посылаемых элементов
INsendtypeтип посылаемых элементов
INdestномер процесса-получателя
INsendtagидентификатор посылаемого сообщения
OUTrecvbufадрес начала расположения принимаемого сообщения
INrecvcountмаксимальное число принимаемых элементов
INrecvtypeтип элементов принимаемого сообщения
INsourceномер процесса-отправителя
INrecvtagидентификатор принимаемого сообщения
INcommкоммуникатор области связи
OUTstatusатрибуты принятого сообщения

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

Неблокирующие коммуникационные операции

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

Функция передачи сообщения без блокировки MPI_Isend

    MPI_ISEND(BUF, COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERROR)
    <type> BUF(*)
    INTEGER COUNT, DATATYPE, DEST, TAG, COMM, REQUEST, IERROR
ТипПараметрОписание
INbufадрес начала расположения передаваемых данных
INcountчисло посылаемых элементов
INdatatypeтип посылаемых элементов
INdestномер процесса-получателя
INtagидентификатор сообщения
INcommкоммуникатор
OUTrequest"запрос обмена"

Возврат из подпрограммы происходит немедленно (immediate), без ожидания окончания передачи данных. Этим объясняется префикс I в именах функций. Поэтому переменную buf повторно использовать нельзя до тех пор, пока не будет погашен "запрос обмена". Это можно сделать с помощью подпрограмм MPI_Wait или MPI_Test, передав им параметр request.

Функция приема сообщения без блокировки MPI_Irecv

    MPI_IRECV(BUF, COUNT, DATATYPE, SOURCE, TAG, COMM, REQUEST, IERROR)
    <type> BUF(*)
    INTEGER COUNT, DATATYPE, SOURCE, TAG, COMM, REQUEST, IERROR
ТипПараметрОписание
OUTbufадрес для принимаемых данных
INcountмаксимальное число принимаемых элементов
INdatatypeтип элементов принимаемого сообщения
INsourceномер процесса-отправителя
INtagидентификатор сообщения
INcommкоммуникатор
OUTrequest"запрос обмена"

Возврат из подпрограммы происходит немедленно, без ожидания окончания приема данных. Определить момент окончания приема можно с помощью подпрограмм MPI_Wait или MPI_Test с соответствующим параметром request.

Функция ожидания завершения неблокирующей операции MPI_Wait

    MPI_WAIT(REQUEST, STATUS, IERROR)
    INTEGER REQUEST, STATUS(MPI_STATUS_SIZE), IERROR
	    
    INOUT 	request 	- "запрос обмена";
    OUT 	status 	- атрибуты сообщения.

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

Функция проверки завершения неблокирующей операции MPI_Test

    MPI_TEST(REQUEST, FLAG, STATUS, IERROR)
    LOGICAL FLAG
    INTEGER REQUEST, STATUS(MPI_STATUS_SIZE), IERROR
			    
    INOUT 	request 	- 	"запрос обмена";
    OUT 	flag 	- 	признак завершенности проверяемой операции;
    OUT 	status 	- 	атрибуты сообщения, если операция завершилась.

Это локальная неблокирующая операция. Если связанная с запросом request операция завершена, возвращается flag = true, а status содержит информацию о завершенной операции. Если проверяемая операция не завершена, возвращается flag = false, а значение status в этом случае не определено.

Рассмотрим пример использования неблокирующих операций и функции MPI_Wait.

			    
      CALL MPI_COMM_RANK(comm, rank, ierr)
      IF (rank.EQ.0) THEN
         CALL MPI_ISEND(a(1), 10, MPI_REAL, 1, tag, comm, request, ierr)
          **** Выполнение вычислений во время передачи сообщения ****
         CALL MPI_WAIT(request, status, ierr)
      ELSE
         CALL MPI_IRECV(a(1), 15, MPI_REAL, 0, tag, comm, request, ierr)
          **** Выполнение вычислений во время приема сообщения ****
	 CALL MPI_WAIT(request, status, ierr)
      END IF

И, напоследок, опишем структуру переменной status.

Назначение полей переменной status:

Поля statusОбращение к полю из FORTRANа
Процесс-отправительstatus(MPI_SOURCE)
Идентификатор сообщенияstatus(MPI_TAG)
Код ошибкиstatus(MPI_ERROR)

Copyright © 1998-2011 Юрий Сбитнев