Programming Taskbook


E-mail:

Пароль:

Регистрация пользователя   Восстановление пароля

English

ЮФУ

Электронный задачник по программированию

©  М. Э. Абрамян (Южный федеральный университет), 1998–2022

 

PT for MPI-2 | Выполнение заданий в параллельном режиме   | Создание заготовки

PrevNext


Создание заготовки для параллельной программы

Процесс выполнения задания с применением задачника PT for MPI-2 начинается с создания заготовки проекта для выбранного задания. К этому проекту уже будут подключены все необходимые библиотеки (связанные с задачником и с выбранной системой MPICH), кроме того, основной файл этого проекта будет содержать важные фрагменты кода, необходимые при выполнении любой параллельной программы.

Для создания заготовки предназначен программный модуль PT4Load, входящий в состав задачника. Проще всего вызвать этот модуль с помощью ярлыка Load.lnk, который автоматически создается в рабочем каталоге учащегося (по умолчанию рабочий каталог имеет имя PT4Work и находится на диске C). После запуска модуля PT4Load на экране появится его окно:

Так выглядит окно, если текущей программной средой задачника является среда Microsoft Visual Studio 2015 для языка C++. Для изменения текущей среды достаточно выполнить в окне щелчок правой кнопкой мыши (или нажать кнопку или клавишу Shift+F10) и выбрать из появившегося контекстного меню новую среду (например «Code::Blocks (C++)»; при этом в заголовке окна появится название выбранной среды).

Вид контекстного меню приведен на следующем рисунке:

Кроме списка доступных сред контекстное меню содержит список доступных вариантов системы MPICH (с указанием текущего варианта), позволяет выбрать язык интерфейса (русский или английский), а также выполнить ряд дополнительных действий по настройке рабочего каталога.

Обратите внимание на группы заданий, начинающиеся с префикса MPI (MPI1Proc и т. д.). Они появятся в списке только после установки задачника по параллельному программированию PT for MPI-2 и только в том случае, если в качестве текущей среды программирования выбрана среда для языка C++.

Определимся с выбором среды программирования, после чего введем в поле «Задание» текст MPI1Proc2 (заметим, что полное имя группы вводить не обязательно; достаточно ввести текст MPI1, однозначно определяющий группу, после чего нажать пробел и указать номер задания 2). В результате кнопка «Загрузка» станет доступной; кроме того, в нижней части окна будет приведено краткое описание выбранной группы и количество входящих в нее заданий:

Нажав кнопку «Загрузка» или клавишу Enter, мы создадим заготовку для указанного задания, которая будет немедленно загружена в выбранную программную среду.

Проект, созданный задачником для языка C++, всегда имеет имя ptprj; это позволяет, в частности, существенно уменьшить количество файлов, создаваемых в рабочем каталоге при выполнении большого количества различных заданий. Он включает ряд файлов, основным из которых является cpp-файл, имя которого совпадает с именем выполняемого задания (в нашем случае MPI1Proc2.cpp). Этот файл автоматически загружается в редактор кода среды программирования; именно в нем необходимо ввести решение задачи. Приведем текст файла MPI1Proc2.cpp:

#include "pt4.h"
#include "mpi.h"
void Solve()
{
    Task("MPI1Proc2");
    int flag;
    MPI_Initialized(&flag);
    if (flag == 0)
        return;
    int rank, size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

}

В начале программы содержатся директивы подключения к ней вспомогательных заголовочных файлов pt4.h и mpi.h. Затем располагается функция Solve, которая должна содержать решение задачи.

При анализе файла MPI1Proc2.cpp возникает естественный вопрос: где находится «стартовая» функция приложения (обычно имеющая имя main или WinMain)? Данная функция размещается в другом файле проекта, поскольку ее содержимое не требует редактирования. В ней производится инициализация задачника, после чего происходит вызов функции Solve с решением, при необходимости перехватываются исключения, которые могут возникнуть при выполнении функции Solve, и в конце выполняются завершающие действия, связанные с анализом полученного решения.

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

Обсудим содержимое функции Solve подробнее. Первым ее оператором является оператор вызова функции Task, инициализирующей требуемое задание. Этот оператор имеется в программах-заготовках для всех заданий, в том числе и не связанных с параллельным программированием. Функция Task реализована в ядре задачника Programming Taskbook (динамической библиотеке) и доступна в программе учащегося благодаря подключенному к ней заголовочному файлу pt4.h. Помимо заголовочного файла pt4.h в рабочем каталоге учащегося должен находиться файл pt4.cpp, содержащий определения функций, объявленных в файле pt4.h.

Оставшиеся операторы функции Solve связаны с библиотекой MPI. Мы уже отмечали, что задачник использует библиотеку MPI, входящую в систему MPICH — широко распространенную бесплатную программную реализацию стандарта MPI для различных операционных систем, в том числе и для Windows. Функции и константы библиотеки MPI доступны программе благодаря подключенному к ней заголовочному файлу mpi.h. Реализация функций из файла mpi.h содержится в объектном файле mpich.lib, который требуется подключать к любому проекту на языках С/C++, использующему библиотеку MPI. Однако в нашем случае это подключение уже выполнено в ходе создания проекта-заготовки, поэтому дополнительных действий, связанных с этим подключением, выполнять не требуется.

Примечание 1. Объектный lib-файл для системы MPICH2 1.3 содержится в подкаталоге MPICH2\lib и имеет имя mpi.lib, однако задачник использует для этой библиотеки название mpich.lib, совпадающее с названием аналогичной библиотеки для версии MPICH 1.2.5 (это позволяет задавать для проектов одинаковые настройки независимо от того, с какой версией системы MPICH они должны быть связаны: к проекту всегда подключается тот вариант библиотеки mpich.lib, который содержится в рабочем каталоге).

Примечание 2. Для подключения к проекту дополнительного lib-файла в среде Visual Studio надо вызвать окно свойств проекта (команда «Project | <имя проекта> Properties…»), перейти в этом окне в раздел «Configuration Properties | Linker | Input» и указать имя подключаемого файла в поле ввода «Additional Dependencies». Если перейти на данный раздел в созданном проекте, то начальный текст в этом поле ввода будет иметь вид «mpich.lib;».

Аналогичные действия надо проделать и в среде Code::Blocks; в ней надо выполнить команду «Project | Build options…», в появившемся окне перейти на вкладку «Linker settings» и указать требуемую библиотеку в разделе «Link libraries».

Вызов функции MPI_Initialized позволяет определить, инициализирован для программы параллельный режим или нет. Если режим инициализирован, то выходной параметр функции принимает значение, отличное от нуля; в противном случае параметр полагается равным нулю. Следует отметить, что инициализация параллельного режима выполняется функцией MPI_Init, которая в приведенном коде отсутствует. Это объясняется тем, что за инициализацию отвечает сам задачник, и выполняется она перед тем, как программа переходит к выполнению кода учащегося. Однако такая инициализация выполняется задачником не всегда. Например, если программа запущена в демо-режиме (для этого достаточно при вызове функции Task дополнить имя задания символом «?»: Task("MPI1Proc2?")), задачник не выполняет инициализацию параллельного режима, поскольку в нем нет необходимости. В этой ситуации вызов в коде учащегося функций MPI (отличных от MPI_Initialized) может привести к некорректной работе программы. Вызов функции MPI_Initialized и следующий за ним условный оператор предназначены для того, чтобы «пропустить» при выполнении программы все операторы, введенные учащимся, если программа запущена не в параллельном режиме.

Два последних оператора программы позволяют определить две характеристики, необходимые для нормальной работы любого процесса любой содержательной параллельной программы: общее количество процессов (функция MPI_Comm_size) и ранг текущего процесса (функция MPI_Comm_rank). Текущим считается процесс, вызвавший данную функцию. Требуемая характеристика возвращается во втором параметре соответствующей функции; первым параметром является коммуникатор, задающий набор процессов. Благодаря вызову этих функций мы можем сразу использовать в нашей программе значения size (общее число процессов в коммуникаторе MPI_COMM_WORLD) и rank (ранг текущего процесса в коммуникаторе MPI_COMM_WORLD; значение ранга обязательно лежит в диапазоне от 0 до size – 1). Обратите внимание на то, что вторые параметры этих функций являются указателями на соответствующие переменные.

Примечание 3. Любая функция MPI возвращает информацию об успешности своего выполнения. В частности, при успешном завершении функция возвращает значение MPI_SUCCESS. Однако, как правило, возвращаемые значения функций MPI не анализируются, а возникающие ошибки обрабатываются специальным обработчиком ошибок (error handler). При выполнении заданий по параллельному программированию с применением задачника PT for MPI-2 используется специальный обработчик ошибок, который определен в задачнике и обеспечивает вывод информации об ошибках в особом разделе окна задачника — разделе отладки. Некоторые возможности MPI, связанные с обработкой ошибок, рассматриваются в заданиях MPI5Comm23–24.

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


PrevNext

 

Рейтинг@Mail.ru

Разработка сайта:
М. Э. Абрамян, В. Н. Брагилевский

Последнее обновление:
01.01.2022