Удобно было бы иметь возможность ожидать завершения любой, определенной или всех операций в списке, а не ждать только специального сообщения.
Вызовы MPI_WAITANY или MPI_TESTANY можно использовать для ожидания завершения одной из нескольких операций.
Вызовы MPI_WAITALL или MPI_TESTALL могут быть использованы для всех ждущих операций в списке. Вызовы WAITSOME или MPI_TESTSOME можно использовать для завершения всех разрешенных операций в списке.
Синтаксис функции MPI_WAITANY представлен ниже.
MPI_WAITANY(count, array_of_requests, index, status)
IN | count | длина списка (целое) | |
INOUT | array_of_requests | массив запросов (массив десрипторов) | |
OUT | index | индекс дескриптора для завершенной операции (целое) | |
OUT | status | статусный объект (статус) |
int MPI_Waitany(int count, MPI_Request *array_of_requests,
int *index, MPI_Status *status)
MPI_WAITANY(COUNT, ARRAY_OF_REQUESTS, INDEX, STATUS, IERROR)
INTEGER COUNT, ARRAY_OF_REQUESTS(*), INDEX, STATUS(MPI_STATUS_SIZE), IERROR
static int MPI::Request::Waitany(int count,
MPI::Request array_of_requests[], MPI::Status& status)
static int MPI::Request::Waitany(int count,
MPI::Request array_of_requests[])
Операция блокирует работу до тех пор, пока не завершится одна из операций из массива активных запросов. Если более, чем одна операция задействована и может окончиться, выполняется произвольный выбор. Операция возвращает в index индекс этого запроса в массиве и возвращает в status статус завершаемого обмена. (Массив индексируется от нуля в языке Си и от единицы в языке ФОРТРАН).
Если запрос был создан операцией неблокирующего обмена, тогда он удаляется и дескриптор запроса устанавливается в MPI_REQUEST_NULL.
Список array_of_request может содержать нуль или неактивные дескрипторы. Если список не содержит активных дескрипторов (список имеет нулевую длину или все элементы являются нулями или неактивны), тогда вызов заканчивается немедленно с index = MPI_UNDEFINED и со статусом empty.
Выполнение MPI_WAITANY(count, array_of_requests, index, status) имеет тот же эффект, что и выполнение MPI_WAIT(&array_of_requests[i], status), где i есть значение, возвращенное в аргументе index (если значение index не MPI_UNDEFINED). MPI_WAITANY с массивом, содержащим один активный элемент, эквивалентно MPI_WAIT.
Синтаксис функции MPI_TESTANY представлен ниже.
MPI_TESTANY(count, array_of_requests, index, flag, status)
IN | count | длина списка (целое) | |
INOUT | array_of_requests | массив запросов (массив дескрипторов) | |
OUT | index | индекс дескриптора для завершенной операции (целое) | |
OUT | flag | true, если одна из операций завершена (логический тип) | |
OUT | status | статусный объкт (статус) |
int MPI_Testany(int count, MPI_Request *array_of_requests,
int *index, int *flag, MPI_Status *status)
MPI_TESTANY(COUNT, ARRAY_OF_REQUESTS, INDEX, FLAG, STATUS, IERROR)
LOGICAL FLAG
INTEGER COUNT, ARRAY_OF_REQUESTS(*), INDEX, STATUS(MPI_STATUS_SIZE), IERROR
static bool MPI::Request::Testany(int count,
MPI::Request array_of_requests[], int& index, MPI::Status& status)
static bool MPI::Request::Testany(int count,
MPI::Request array_of_requests[], int& index)
Функция тестирует завершение либо одной, либо никакой из операций, связанных с активными дескрипторами. В первом случае она возвращает flag = true, индекс этого запроса в массиве index и статус этой операции в status; если запрос был создан вызовом неблокирующего обмена, тогда запрос удаляется и дескриптор устанавливается в MPI_REQUEST_NULL. (Массив индексируется от нуля в языке Си и от единицы в языке ФОРТРАН). В последнем случае (не завершено никакой операции) возвращается flag = false, значение MPI_UNDEFINED в index и состояние аргумента status является неопределенным.
Массив может содержать нуль или неактивные дескрипторы. Если массив не содержит активных дескрипторов, тогда вызов заканчивается немедленно с flag = true, index = MPI_UNDEFINED, и status = empty.
Если массив запросов содержит активные дескрипторы, тогда выполнение
MPI_TESTANY(count, array_of_requests, index, status) имеет
тот же самый эффект, что и выполнение
MPI_TEST(&array_of_requests[i], flag, status)
для i=0, 1, ..., count-1 в некотором произвольном порядке,
пока один вызов не возвратит flag = true, или все вызовы не могут быть
выполнены. В первом случае индекс устанавливается на последнее значение i,
и в последнем случае устанавливается в MPI_UNDEFINED.
MPI_TESTANY с массивом, содержащим один активный элемент,
эквивалентен MPI_TEST.
Объяснение: Функция MPI_TESTANY заканчивается с flag = true точно в момент, когда функция MPI_WAITANY возвращает управление ; обе функции возвращают в этом случае одинаковые значения остающихся параметров. Поэтому блокирующий вызов MPI_WAITANY может быть легко замещен неблокирующим MPI_TESTANY. Те же отношения сохраняются и для других пар функций Wait и Test, определенных в этом разделе.[]
Синтаксис функции MPI_WAITALL представлен ниже.
MPI_WAITALL(count, array_of_requests, array_of_statuses)
IN | count | длина списков (целое) | |
INOUT | array_of_requests | массив запросов (массив дескрипторов) | |
OUT | array_of_statuses | массив статусных объектов (массив статусов) |
int MPI_Waitall (int count, MPI_Request *array_of_requests,
MPI_Status *array_of_statuses)
MPI_WAITALL(COUNT, ARRAY_OF_REQUESTS, ARRAY_OF_STATUSES, IERROR)
INTEGER COUNT, ARRAY_OF_REQUESTS(*)
INTEGER ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*), IERROR
static void MPI::Request::Waitall (int count,
MPI::Request array_of_requests[], MPI::Status array_of_statuses[])
static void MPI::Request::Waitall (int count,
MPI::Request array_of_requests[])
Функция блокирует работу, пока все операции обмена, связанные с активными дескрипторами в списке, не завершатся, и возвращает статус всех операций (это включает случай, когда в списке нет активных дескрипторов). Оба массива имеют то же самое количество элементов. Элемент с номером i в array_of_statuses устанавливается в возвращаемый статус i-ой операции. Запросы, созданные операцией неблокирующего обмена, удаляются и соответствующие дескрипторы устанавливаются в MPI_REQUEST_NULL. Список может содержать нуль или неактивные дескрипторы. Вызов устанавливает статус каждого такого элемента в состояние empty.
Если ошибок нет, то вызов MPI_WAITALL(count, array_of_requests, array_of_statuses) имеет тот же эффект, что и вызов MPI_WAIT(&array_of_request[i], &array_of_statuses[i]) для i=0, ..., count-1 в некотором произвольном порядке. MPI_WAITALL с массивом длины один эквивалентен MPI_WAIT.
Когда один или более обменов, завершенных обращением к MPI_WAITALL, оказались неудачны, желательно возвратить специальную информацию по каждому обмену. Функция MPI_WAITALL возвращает в таком случае код MPI_ERR_IN_STATUS и устанавливает в поля ошибки каждого статуса специфический код ошибки. Этот код равен MPI_SUCCESS, если обмен завершен, или другому коду, если обмен не состоялся; он может иметь значение MPI_ERR_PENDING, если он и не завершен, и не в состоянии отказа. Функция MPI_WAITALL будет возвращать MPI_SUCCESS, если никакой из запросов не вызвал ошибку или будет возвращать специальный код ошибки, если запрос не выполнился по другим причинам (таким, как неверный аргумент). В таком случае функция не будет корректировать поле ошибки в статусе.
Объяснение: Стандарт упрощает обработку ошибок в приложениях. Прикладному коду нужно только проверить результат функции (единственный), чтобы выяснить, есть ли ошибка. Ему необходимо проверить каждый индивидуальный статус только в том случае, когда ошибка есть.[]
Синтаксис функции MPI_TESTALL представлен ниже.
MPI_TESTALL(count, array_of_requests, flag, array_of_statuses)
IN | count | длина списка (целое) | |
INOUT | array_of_requests | массив запросов (массив дескрипторов) | |
OUT | flag | (логический тип) | |
OUT | array_of_statuses | массив статусных объектов(массив статусов) |
int MPI_Testall(int count, MPI_Request *array_of_requests,
int *flag, MPI_Status *array_of_statuses)
MPI_TESTALL(COUNT, ARRAY_OF_REQUESTS, FLAG, ARRAY_OF_STATUSES, IERROR)
LOGICAL FLAG
INTEGER COUNT, ARRAY_OF_REQUESTS(*),
ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*), IERROR
static bool MPI::Request::Testall(int count,
MPI::Request array_of_requests[], MPI::Status array_of_statuses[])
static bool MPI::Request::Testall(int count, MPI::Request array_of_requests[])
Функция возвращает flag = true, если обмены, связанные с активными дескрипторами в массиве, завершены (это включает случай, когда в списке нет активных дескрипторов). В этом случае каждый статусный элемент, который соответствует активному дескриптору, устанавливается в статус соответствующего обмена; если запрос был создан вызовом неблокирующего обмена, то он удаляется и дескриптор устанавливается в MPI_REQUEST_NULL. Каждый статусный элемент, который соответствует нулю или неактивному дескриптору, устанавливается в состояние empty.
В противном случае возвращается flag = false, никакие запросы не модифицируются и значения статусных элементов неопределенные. Операция является локальной.
Ошибки, которые имеют место при выполнении MPI_TESTALL, обрабатываются также, как и в случае MPI_WAITALL.
Синтаксис функции MPI_WAITSOME представлен ниже.
MPI_WAITSOME (incount, array_of_requests, outcount,
array_of_indices, array_of_statuses)
IN | incount | длина массива запросов (целое) | |
INOUT | array_of_requests | массив запросов (массив дескрипторов) | |
OUT | outcount | число завершенных запросов (целое) | |
OUT | array_of_indices | массив индексов операций, которые завершены (мас-сив целых) | |
OUT | array_of_statuses | массив статусных операций для завершенных опера-ций (массив статусов) |
int MPI_Waitsome (int incount, MPI_Request *array_of_requests,
int *outcount, int *array_of_indices, MPI_Status *array_of_statuses)
MPI_WAITSOME (INCOUNT, ARRAY_OF_REQUESTS, OUTCOUNT, ARRAY_OF_INDICES,
ARRAY_OF_STATUSES, IERROR)
INTEGER INCOUNT, ARRAY_OF_REQUESTS(*), OUTCOUNT, ARRAY_OF_INDICES(*),
ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*), IERROR
static int MPI::Request::Waitsome(int incount,
MPI::Request array_of_requests[], int array_of_indices[],
MPI::Status array_of_statuses[])
static int MPI::Request::Waitsome(int incount,
MPI::Request array_of_requests[], int array_of_indices[ ])
Функция ожидает, пока по крайней мере одна операция, связанная с активным дескриптором в списке, не завершится. Она возвращает в outcount число зопросов из списка array_of_indices, которые завершены. В первую outcount ячейку массива array_of_indices возвращаются индексы этих операций (индекс внутри array_of_requests; массив индексируется от нуля в языке Си и от единицы в языке ФОРТРАН). В первую ячейку outcount массива array_of_status поступает статус этих завершенных операций. Если завершенный запрос был создан вызовом неблокирующего обмена, то он удаляется и связанный дескриптор устанавливается в MPI_REQUEST_NULL.
Если список не содержит активных дескрипторов, то вызов заканчивается немедленно со значением outcount = MPI_UNDEFINED.
Если один или более обменов, завершенных MPI_WAITSOME, не могут быть выполнены, то надо возвращать по каждому обмену специфическую информацию. При этом аргументы outcount, array_of_indices и array_of_statuses будут индицировать завершение всех обменов, успешных или неуспешных. Вызов будет возвращать код ошибки MPI_ERR_IN_STATUS и устанавливать поле ошибки каждого возвращенного статуса, чтобы указать на успешное завершение или возвратить специфический код ошибки. Вызов будет возвращать MPI_SUCCESS, если ни один запрос не содержал ошибки, и будет возвращен специальный код ошибки, если запрос не может быть выполнен по какой-то причине (такой, как неправильный аргумент). В таких случаях поля ошибок статуса не будут корректироваться.
Синтаксис функции MPI_TESTSOME представлен ниже.
MPI_TESTSOME(incount, array_of_requests, outcount,
array_of_indices, array_of_statuses)
IN | incount | длина массива запросов (целое) | |
INOUT | array_of_requests | массив запросов(массив дескрипторов) | |
OUT | outcount | число завершенных запросов (целое) | |
OUT | array_of_indices | массив индексов завершенных операций (массив целых) | |
OUT | array_of_statuses | массив статусных объектов завешенных операций (массив статусов) |
int MPI_Testsome(int incount, MPI_Request *array_of_requests,
int *outcount, int *array_of_indices, MPI_Status *array_of_statuses)
MPI_TESTSOME(INCOUNT, ARRAY_OF_REQUESTS, OUTCOUNT, ARRAY_OF_INDICES,
ARRAY_OF_STATUSES, IERROR)
INTEGER INCOUNT, ARRAY_OF_REQUESTS(*), OUTCOUNT, ARRAY_OF_INDICES(*),
ARRAY_OF_STATUSES(MPI_STATUS_SIZE,*), IERROR
static int MPI::Request::Testsome(int incount,
MPI::Request array_of_requests[], int array_of_indices[],
MPI::Status array_of_statuses[])
static int MPI::Request::Testsome(int incount,
MPI::Request array_of_requests[], int array_of_indices[])
Функция MPI_TESTSOME ведет себя подобно MPI_WAITSOME за исключением того, что заканчивается немедленно. Если ни одной операции не завершено, она возвращает outcount = 0. Если не имеется активных дескрипторов в списке, она возвращает outcount = MPI_UNDEFINED.
MPI_TESTSOME является локальной операцией, которая заканчивается немедленно, тогда как MPI_WAITSOME будет блокировать процесс до завершения обменов, если в списке содержится хотя бы один активный дескриптор. Оба вызова выполняют требование однозначности: если запрос на прием повторно появляется в списке запросов, передаваемых MPI_WAITSOME или MPI_TESTSOME, и соответствующая посылка была инициирована, тогда прием будет рано или поздно завершен успешно, если передача не закрыта другим приемом; аналогичная ситуация для запросов посылок.
Ошибки при выполнении MPI_TESTSOME обрабатываются также, как и для MPI_WAITSOME.
Совет пользователям: Использование MPI_TESTSOME представляется более эффективным, чем использование MPI_TESTANY. Первая функция возвращает информацию по всем завершенным обменам, для последней требуется вызов для каждого обмена, который завершается.
Сервер с множественными клиентами может использовать MPI_WAITSOME, чтобы не лишать обмена ни одного клиента. Клиент посылает сообщение серверу с сервисным запросом. Сервер вызывает MPI_WAITSOME с одним приемным требованием для каждого клиента и затем обрабатывает все приемы, которые завершены. Если вместо MPI_WAITSOME использован вызов MPI_WAITANY, тогда один клиент мог бы остаться без возможности обмена, в то время, как другие клиенты всегда проходили бы первыми.[]
Совет разработчикам: MPI_TESTSOME должен завершать как можно большее число ждущих коммуникаций.[]
Пример 3.15 Код клиента - сервера (имеет место невозможность обмена).
CALL MPI_COMM_SIZE(comm, size, ierr)
CALL MPI_COMM_RANK(comm, rank, ierr)
IF(rank > 0) THEN ! код клиента
DO WHILE(.TRUE.)
CALL MPI_ISEND(a, n, MPI_REAL, 0, tag, comm, request, ierr)
CALL MPI_WAIT(request, status, ierr)
END DO
ELSE ! rank=0 - код сервера
DO i=1, size-1
CALL MPI_IRECV(a(1,i), n, MPI_REAL, i tag,
comm, request_list(i), ierr)
END DO
DO WHILE(.TRUE.)
CALL MPI_WAITANY(size-1, request_list, index, status, ierr)
CALL DO_SERVICE(a(1,index)) ! дескриптор одного сообщения
CALL MPI_IRECV(a(1, index), n, MPI_REAL, index, tag,
comm, request_list(index), ierr)
END DO
END IF
Пример 3.16 Код с использованием MPI_WAITSOME.
CALL MPI_COMM_SIZE(comm, size, ierr)
CALL MPI_COMM_RANK(comm, rank, ierr)
IF(rank > 0) THEN ! код клиента
DO WHILE(.TRUE.)
CALL MPI_ISEND(a, n, MPI_REAL, 0, tag, comm, request, ierr)
CALL MPI_WAIT(request, status, ierr)
END DO
ELSE ! rank=0 - код сервера
DO i=1, size-1
CALL MPI_IRECV(a(1,i), n, MPI_REAL, i, tag,
comm, requests(i), ierr)
END DO
DO WHILE(.TRUE.)
CALL MPI_WAITSOME(size, request_list, numdone,
indices, statuses, ierr)
DO i=1, numdone
CALL DO_SERVICE(a(1, indices(i)))
CALL MPI_IRECV(a(1, indices(i)), n, MPI_REAL, 0, tag,
comm, requests(indices(i)), ierr)
END DO
END DO
END IF