next up previous contents
Next: Проба и отмена Up: Неблокирующий обмен Previous: Семантика неблокирующих коммуникаций   Contents

Множественные завершения

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

Вызовы 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


next up previous contents
Next: Проба и отмена Up: Неблокирующий обмен Previous: Семантика неблокирующих коммуникаций   Contents
Alex Otwagin 2002-12-10