Операции MPI_PROBE и MPI_IPROBE позволяют проверить входные сообщения без их реального приема. Пользователь затем может решить, как ему принимать эти сообщения, основываясь на информации, возвращенной при пробе (преимущественно, на информации, возвращенной аргументом status). В частности, пользователь может выделить память для приемного буфера по величине опробованного сообщения.
Операция MPI_CANCEL позволяет отменить ждущие сообщения. Инициация операций получения или отправки связывает пользовательские ресурсы (буфера процесса-получателя или отправителя) и отмена может оказаться необходимой, чтобы освободить эти ресурсы.
Синтаксис функции MPI_IPROBE представлен ниже.
MPI_IPROBE(source, tag, comm, flag, status)
IN | source | номер процесса-отправителя или MPI_ANY_SOURCE (целое) | |
IN | tag | значение тэга или MPI_ANY_TAG (целое) | |
IN | comm | коммуникатор (дескриптор) | |
OUT | flag | (логическое значение) | |
OUT | status | статус (статус) |
int MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status)
MPI_IPROBE(SOURCE, TAG, COMM, FLAG, STATUS, IERROR)
LOGICAL FLAG
INTEGER SOURCE, TAG, COMM, STATUS(MPI_STATUS_SIZE), IERROR
bool MPI::Comm::Iprobe(int source, int tag, MPI::Status& status) const
bool MPI::Comm::Iprobe(int source, int tag) const
Функция MPI_IPROBE (source, tag, comm, flag, status) возвращает flag = true, если имеется сообщение, которое может быть получено и которое соответствует образцу, описанному аргументами source, tag, и comm. Вызов соответствует тому же сообщению, которое было бы получено с помощью вызова MPI_RECV (..., source, tag, comm, status), выполненного на той же точке программы, и возвращает статус с теми же значениями, которые были бы возвращены MPI_RECV(). Другими словами, вызов возвращает flag = false, и оставляет статус неопределенным.
Если MPI_IPROBE возвращает flag = true, тогда содержание статусного объекта может быть впоследствии получено так, как описано в разделе 3.2.5, с целью определить источник, тэг и длину опробованного сообщения. Последующий прием, выполненный с тем же самым контекстом и тэгом, возвращенным в status вызовом MPI_IPROBE, будет получать сообщение, которое соответствует пробе, если после пробы не вмешается какое-либо другое сообщение. Если принимающий процесс является многопоточным, то ответственность за выполнение последнего условия возлагается на пользователя.
Аргумент source функции MPI_PROBE может быть MPI_ANY_SOURCE, это позволяет опробовать сообщения из произвольного источника и/или с произвольным тэгом. Однако, специфический контекст обмена обязан создаваться только при помощи аргумента comm.
Сообщение не обязательно должно быть получено сразу после опробования, кроме того оно может опробоваться несколько раз перед его получением.
Синтаксис функции MPI_PROBE представлен ниже.
MPI_PROBE (source, tag, comm, status)
IN | source | номер источника или MPI_ANY_SOURCE (целое) | |
IN | tag | значение тэга или MPI_ANY_TAG (целое) | |
IN | comm | коммуникатор (дескриптор) | |
OUT | status | статус (статус) |
int MPI_Probe(int source, int tag, MPI_Comm comm, MPI_Status *status)
MPI_PROBE(SOURCE, TAG, COMM, STATUS, IERROR)
INTEGER SOURCE, TAG, COMM, STATUS(MPI_STATUS_SIZE), IERROR
void MPI::Comm::Probe(int source, int tag, MPI::Status& status) const
void MPI::Comm::Probe(int source, int tag) const
MPI_PROBE ведет себя подобно MPI_IPROBE, исключая тот факт, что функция MPI_PROBE является блокирующей и заканчивается только после того, как соответствующее сообщение было найдено.
MPI реализация MPI_PROBE и MPI_IPROBE нуждается в гарантии продвижения: если обращение к MPI_PROBE уже было запущено процессом, и посылка, которая соответствует пробе, уже инициирована тем же процессом, тогда вызов MPI_PROBE будет завершен, если сообщение не будет получено другой конкурирующей операцией приема (которая выполняется другой ветвью опробуемого процесса). Аналогично, если процесс ожидает выполнения MPI_IPROBE и соответствующее сообщение было запущено, тогда обращение к MPI_IPROBE рано или поздно возвратит flag = true, если сообщение не получено другой конкурирующей приемной операцией.
Пример 3.17 Использование блокирующей пробы для ожидания входного сообщения.
CALL MPI_COMM_RANK(comm, rank, ierr)
IF (rank.EQ.0) THEN
CALL MPI_SEND(i, 1, MPI_INTEGER, 2, 0, comm, ierr)
ELSE IF(rank.EQ.1) THEN
CALL MPI_SEND(x, 1, MPI_REAL, 2, 0, comm, ierr)
ELSE ! rank.EQ.2
DO i=1, 2
CALL MPI_PROBE(MPI_ANY_SOURCE, 0,
comm, status, ierr)
IF (status(MPI_SOURCE) = 0) THEN
100 CALL MPI_RECV(i,1,MPI_INTEGER,0,0,comm, status, ierr)
ELSE
200 CALL MPI_RECV(x,1,MPI_REAL,1,0,comm, status, ierr)
END IF
END DO
END IF
Каждое сообщение принимается с правильным типом.
Пример 3.18 Программа подобна предыдущей, но теперь в ней имеется проблема.
CALL MPI_COMM_RANK(comm, rank, ierr)
IF (rank.EQ.0) THEN
CALL MPI_SEND(i, 1, MPI_INTEGER, 2, 0, comm, ierr)
ELSE IF(rank.EQ.1) THEN
CALL MPI_SEND(x, 1, MPI_REAL, 2, 0, comm, ierr)
ELSE
DO i=1, 2
CALL MPI_PROBE(MPI_ANY_SOURCE, 0,
comm, status, ierr)
IF (status(MPI_SOURCE) = 0) THEN
100 CALL MPI_RECV(i, 1, MPI_INTEGER, MPI_ANY_SOURCE,
0, comm, status, ierr)
ELSE
200 CALL MPI_RECV(x, 1, MPI_REAL, MPI_ANY_SOURCE,
0, comm, status, ierr)
END IF
END DO
END IF
Здесь пример 3.17 слегка модифицирован, используется MPI_ANY_SOURCE, как аргумент sourse в двух вызовах приема, обозначенных метками 100 и 200. Теперь программа некорректна: операция приема может получать сообщение, которое отличается от сообщения, опробованного предыдущим обращением к MPI_PROBE.
Совет разработчикам: Вызов MPI_PROBE (source, tag, comm, status) будет соответствовать сообщению, которое было бы получено функцией MPI_RECV (...source, tag, comm, status), выполненной в этой же точке программы. Предположим, что это сообщение имеет источник s, тэг t и коммуникатор c. Если тэг имел в вызове пробы значение MPI_ANY_TAG, тогда опробованное значение будет самым ранним ждущим сообщением от источника с коммуникатором с и любым тэгом; в любом случае опробованное сообщение будет самым ранним ждущим сообщением от источника s, с тэгом t и коммуникатором c. Операция приема, выполненная после пробы, которая использует тот же самый коммуникатор, как и проба, и использующая тэг и источник, возвращенные пробой, обязана принять это сообщение, если оно уже не было принято другой приемной операцией.[]
Синтаксис функции MPI_CANCEL представлен ниже.
MPI_CANCEL (request)
IN | request | коммуникационный запрос (дескриптор) |
int MPI_Cancel(MPI_Request *request)
MPI_CANCEL(REQUEST, IERROR)
INTEGER REQUEST, IERROR
void MPI::Request::Cancel () const
Обращение к MPI_CANCEL маркирует для отмены ждущие неблокирующие операции обмена (передачи или приема). Вызов cancel является локальным. Он заканчивается немедленно, возможно перед действительной отменой обмена. После маркировки необходимо завершить эту операцию обмена, используя вызов MPI_REQUEST_FREE, MPI_WAIT или MPI_TEST (или любые производные операции).
Если обмен маркирован для отмены, тогда вызов MPI_WAIT для этой операции гарантирует завершение, невзирая на активность других процессов (то есть MPI_WAIT ведет себя как локальная функция); аналогично, если MPI_TEST вызывается повторно в цикле занятого ожидания для отмены обмена, тогда MPI_TEST будет неизбежно успешно закончен.
MPI_CANCEL может быть использован для отмены обмена, который использует персистентный запрос (см. раздел 3.9), тем же способом, который используется для неперсистентных запросов. Успешная отмена отменяет активный обмен, но не сам запрос. После обращения к MPI_CANCEL и затем к MPI_WAIT или MPI_TEST запрос становится неактивным и может быть активирован для нового обмена.
Успешная отмена буферизованной передачи освобождает буферное пространство, занятое ждущим сообщением.
Должно выполняться следующее условие: либо отмена имеет успех, либо имеет успех обмен, но не обе ситуации вместе. Если передача маркирована для отмены, тогда обязательно должна быть ситуация, когда либо передача завершается нормально (посланное сообщение принято процессом назначения), или передача отменена успешно (никакая часть сообщения не принята по адресу назначения). Тогда любой соответствующий прием закрывается другой передачей. Если прием маркирован для отмены, тогда обязан быть случай, когда прием завершился нормально, или этот прием успешно отменен (никакая часть приемного буфера не изменена). Тогда любая соответствующая передача должна быть удовлетворена другим приемом.
Если операция была отменена, тогда информация об этом будет возвращена в в аргумент статуса операции, которая завершает обмен.
Синтаксис функции MPI_TEST_CANCELLED представлен ниже.
MPI_TEST_CANCELLED (status, flag)
IN | status | статус (статус) | |
OUT | flag | (логический тип) |
int MPI_Test_cancelled(MPI_Status *status, int *flag)
MPI_TEST_CANCELLED(STATUS, FLAG, IERROR)
LOGICAL FLAG
INTEGER STATUS(MPI_STATUS_SIZE), IERROR
bool MPI::Status::Is_cancelled () const
Функция MPI_TEST_CANCELLED возвращает flag = true, если обмен, связанный со статусным объектом, был отменен успешно. В этом случае все другие поля статуса (такие как count или tag) не определены. В противном случае возвращается flag = false. Если приемная операция может быть отменена, то сначала можно вызвать MPI_TEST_CANCELLED, чтобы проверить, была ли отменена операция (перед проверкой других полей возвращенного статуса).
Совет пользователям: Отмена может быть дорогостоящей операцией, которую следует использовать в виде исключения.[]
Совет разработчикам: Если операция передачи использует ``жадный'' (``eager'') протокол (данные передаются получателю еще до того, как инициирован соответствующий прием), тогда отмена этой передачи может потребовать обмена с предполагаемым получателем, чтобы освободить занятые буфера. На некоторых системах это может потребовать прерывания предполагаемого процесса-получателя. Заметим, что хотя для реализации MPI_CANCEL может потребоваться обмен, это все еще локальная операция, поскольку ее завершение не зависит от кода, выполняемого другими процессами. Если обработка необходима на другом процессе, это должно быть прозрачно для приложения (отсюда необходимость прерывания и наличия обработчика прерываний).[]