Неблокирующие обмены
Презентацию к данной лекции Вы можете скачать здесь.
Общая характеристика неблокирующих обменов
Вызов подпрограммы неблокирующей передачи инициирует, но не завершает ее. Завершиться выполнение подпрограммы может еще до того, как сообщение будет скопировано в буфер передачи.
Применение неблокирующих операций улучшает производительность программы, поскольку в этом случае допускается перекрытие (то есть одновременное выполнение) вычислений и обменов. Передача данных из буфера или их считывание может происходить одновременно с выполнением процессом другой работы.
Для завершения неблокирующего обмена требуется вызов дополнительной процедуры, которая проверяет, скопированы ли данные в буфер передачи.
При неблокирующем обмене возвращение из подпрограммы обмена происходит сразу, но запись в буфер или считывание из него после этого производить нельзя - сообщение может быть еще не отправлено или не получено и работа с буфером может "испортить" его содержимое.
Неблокирующий обмен выполняется в два этапа:
- инициализация обмена;
- проверка завершения обмена.
Разделение этих шагов делает необходимым маркировку каждой операции обмена, которая позволяет целенаправленно выполнять проверки завершения соответствующих операций.
Для маркировки в неблокирующих операциях используются идентификаторы операций обмена
Неблокирующие передача и приём
Инициализация неблокирующей стандартной передачи выполняется подпрограммами MPI_I[S, B, R]send. Стандартная неблокирующая передача выполняется подпрограммой:
int MPI_Isend(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request) MPI_Isend(buf, count, datatype, dest, tag, comm, request, ierr)
Входные параметры этой подпрограммы аналогичны аргументам подпрограммы MPI_Send.
Выходной параметр request - идентификатор операции
Инициализация неблокирующего приема выполняется при вызове подпрограммы:
int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request) MPI_Irecv(buf, count, datatype, source, tag, comm, request, ierr)
Назначение аргументов здесь такое же, как и в ранее рассмотренных подпрограммах, за исключением того, что указывается ранг не адресата, а источника сообщения (source).
Вызовы подпрограмм неблокирующего обмена формируют запрос на выполнение операции обмена и связывают его с идентификатором операции request. Запрос идентифицирует свойства операции обмена:
- режим;
- характеристики буфера обмена;
- контекст;
- тег и ранг.
Запрос содержит информацию о состоянии ожидающих обработки операций обмена и может быть использован для получения информации о состоянии обмена или для ожидания его завершения.
Проверка выполнения неблокирующих обменов
Проверка выполнения обмена
Проверка фактического выполнения передачи или приема в неблокирующем режиме осуществляется с помощью вызова подпрограмм ожидания, блокирующих работу процесса до завершения операции или неблокирующих подпрограмм проверки, возвращающих логическое значение "истина", если операция выполнена
В том случае, когда одновременно несколько процессов обмениваются сообщениями, можно использовать проверки, которые применяются одновременно к нескольким обменам.
Есть три типа таких проверок:
- проверка завершения всех обменов;
- проверка завершения любого обмена из нескольких;
- проверка завершения заданного обмена из нескольких.
Каждая из этих проверок имеет две разновидности:
- "ожидание";
- "проверка".
Блокирующие операции проверки
Подпрограмма MPI_Wait блокирует работу процесса до завершения приема или передачи сообщения:
int MPI_Wait(MPI_Request *request, MPI_Status *status) MPI_Wait(request, status, ierr)
Входной параметр request - идентификатор операции обмена, выходной - статус (status).
Успешное выполнение подпрограммы MPI_Wait после вызова MPI_Ibsend подразумевает, что буфер передачи можно использовать вновь, то есть пересылаемые данные отправлены или скопированы в буфер, выделенный при вызове подпрограммы MPI_Buffer_attach.
В этот момент уже нельзя отменить передачу. Если не будет зарегистрирован соответствующий прием, буфер нельзя будет освободить. В этом случае можно применить подпрограмму MPI_Cancel, которая освобождает память, выделенную подсистеме коммуникаций.
Проверка завершения всех обменов
Проверка завершения всех обменов выполняется подпрограммой:
int MPI_Waitall(int count, MPI_Request requests[], MPI_Status statuses[]) MPI_Waitall(count, requests, statuses, ierr)
При вызове этой подпрограммы выполнение процесса блокируется до тех пор, пока все операции обмена, связанные с активными запросами в массиве requests, не будут выполнены. Возвращается статус этих операций. Статус обменов содержится в массиве statuses. count - количество запросов на обмен (размер массивов requests и statuses).
В результате выполнения подпрограммы MPI_Waitall запросы, сформированные неблокирующими операциями обмена, аннулируются, а соответствующим элементам массива присваивается значение MPI_REQUEST_NULL.
В случае неуспешного выполнения одной или более операций обмена подпрограмма MPI_Waitall возвращает код ошибки MPI_ERR_IN_STATUS и присваивает полю ошибки статуса значение кода ошибки соответствующей операции.
Если операция выполнена успешно, полю присваивается значение MPI_SUCCESS, а если не выполнена, но и не было ошибки - значение MPI_ERR_PENDING. Это соответствует наличию запросов на выполнение операции обмена, ожидающих обработки.
Проверка завершения любого числа обменов
Проверка завершения любого числа обменов выполняется подпрограммой:
int MPI_Waitany(int count, MPI_Request requests[], int *index, MPI_Status *status) MPI_Waitany(count, requests, index, status, ierr)
Выполнение процесса блокируется до тех пор, пока, по крайней мере, один обмен из массива запросов (requests) не будет завершен.
Входные параметры:
- requests - запрос;
- count - количество элементов в массиве requests.
Выходные параметры:
- index - индекс запроса (в языке C это целое число от 0 до count – 1, а в языке Fortran от 1 до count) в массиве requests;
- status - статус.
Неблокирующие процедуры проверки
Подпрограмма MPI_Test выполняет неблокирующую проверку завершения приема или передачи сообщения:
int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status) MPI_Test(request, flag, status, ierr)
Входной параметр: идентификатор операции обмена request.
Выходные параметры:
- flag - "истина", если операция, заданная идентификатором request, выполнена;
- status - статус выполненной операции.
Неблокирующая проверка завершения всех обменов
Подпрограмма MPI_Testall выполняет неблокирующую проверку завершения приема или передачи всех сообщений:
int MPI_Testall(int count, MPI_Request requests[], int *flag, MPI_Status statuses[]) MPI_Testall(count, requests, flag, statuses, ierr)
При вызове возвращается значение флага (flag) "истина", если все обмены, связанные с активными запросами в массиве requests, выполнены. Если завершены не все обмены, флагу присваивается значение "ложь", а массив statuses не определен.
Параметр count - количество запросов.
Каждому статусу, соответствующему активному запросу, присваивается значение статуса соответствующего обмена.
Неблокирующая проверка любого числа обменов
Подпрограмма MPI_Testany выполняет неблокирующую проверку завершения приема или передачи сообщения:
int MPI_Testany(int count, MPI_Request requests[], int *index, int *flag, MPI_Status *status) MPI_Testany(count, requests, index, flag, status, ierr)
Смысл и назначение параметров этой подпрограммы те же, что и для подпрограммы MPI_Waitany. Дополнительный аргумент flag, принимает значение "истина", если одна из операций завершена.
Блокирующая подпрограмма MPI_Waitany и неблокирующая MPI_Testany взаимозаменяемы, как и другие аналогичные пары.