|
|
Создание заготовки для параллельной программы
Процесс выполнения задания с применением задачника Programming
Taskbook обычно начинается с создания проекта-заготовки для выбранного
задания. Особенно удобно использовать такую заготовку для заданий по
параллельному программированию, поскольку в нее уже будут входить
важные фрагменты кода, необходимые при выполнении любой
параллельной программы. Для создания заготовки воспользуемся
программным модулем PT4Load, входящим в состав задачника. Вызвать
этот модуль можно с помощью ярлыка Load.lnk, который
автоматически создается в рабочем каталоге учащегося
(в среде PascalABC.NET для вызова модуля PT4Load предназначена команда меню
«Модули | Создать шаблон программы»;
можно также использовать кнопку на панели инструментов).
При этом на экране появится окно модуля PT4Load.

Так выглядит окно, если текущей программной средой задачника
является среда Free Pascal Lazarus. Для изменения текущей среды
достаточно выполнить в окне щелчок правой кнопкой мыши и выбрать из
появившегося контекстного меню новую среду (например,
«Microsoft Visual C++ 2008»; при этом в заголовке окна
появится текст «[VCNET3]»).
Обратите внимание на группы MPIBegin и MPIDebug, указанные в списке
доступных групп заданий. Их наличие означает, что к базовому варианту задачника
Programming Taskbook подключено его расширение: задачник по параллельному
программированию Programming Taskbook for MPI. Заметим, что если выбрать
программную среду, не связанную с Паскалем или C++ (например,
Microsoft Visual Basic любой версии), то группы MPIBegin и MPIDebug
в списке будут отсутствовать.
Определимся с выбором среды программирования, после чего введем
в поле «Задание» текст MPIBegin1. В результате кнопка
«Загрузка» станет доступной и, нажав ее (или клавишу
[Enter]), мы создадим заготовку для указанного задания, которая
будет немедленно загружена в выбранную программную среду.
В случае использования Паскаля для среды Lazarus в нее будет
загружен файл MPIBegin1.lpr, содержащий следующий текст:
[Pascal]
program MPIBegin1;
uses PT4, MPI;
var
flag, size, rank: integer;
begin
Task('MPIBegin1');
MPI_Initialized(flag);
if flag = 0 then exit;
MPI_Comm_size(MPI_COMM_WORLD, size);
MPI_Comm_rank(MPI_COMM_WORLD, rank);
end.
Файл с таким же содержанием будет создан и при использовании среды Borland Delphi
или PascalABC.NET; другим будет только расширение файла:
dpr для среды Delphi, pas для среды PascalABC.NET.
Если же используется язык C++ для среды Visual Studio, то будет
создан и загружен в эту среду файл MPIBegin1.cpp, начинающийся со
следующего текста (завершающая часть файла, не показанная здесь,
является служебной и не требует редактирования):
[C++]
#include <windows.h>
#pragma hdrstop
#include "pt4.h"
#include "mpi.h"
void Solve()
{
Task("MPIBegin1");
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);
}
Программа-заготовка для заданий по параллельному
программированию содержит дополнительные операторы, отсутствующие
в заготовках для «непараллельных» заданий. Эти операторы
должны использоваться практически в любой параллельной MPI-программе,
поэтому, чтобы не вынуждать учащегося набирать их каждый
раз заново, они автоматически добавляются к программе при ее создании.
Обсудим операторы программы-заготовки подробнее. Первым
оператором является оператор вызова процедуры Task,
инициализирующей требуемое задание. Этот оператор
имеется в программах-заготовках для всех заданий, в том числе и не
связанных с параллельным программированием. Заметим, что процедура
Task реализована в ядре задачника Programming Taskbook (динамической
библиотеке) и доступна из программы учащегося благодаря
подключенному к ней модулю PT4.pas (для Паскаля) или заголовочному
файлу pt4.h (для C++). Помимо заголовочного файла pt4.h в рабочем
каталоге учащегося должен находиться файл pt4.cpp, содержащий
определения функций, объявленных в файле pt4.h.
Оставшиеся операторы связаны с библиотекой MPI. Задачник
использует библиотеку MPI, входящую в систему MPICH широко
распространенную бесплатную программную реализацию стандарта MPI
для различных операционных систем, в том числе и для Windows.
Функции и константы библиотеки MPI доступны программе благодаря
подключенному к ней модулю MPI.pas (для Паскаля) или заголовочному
файлу mpi.h (для C++). Отметим, что реализация функций из файла mpi.h
содержится в файле mpich.lib, который требуется явным образом
подключить к любому проекту на языках С/C++, использующему
библиотеку MPI. Однако в нашем случае это подключение уже
выполнено в ходе создания проекта-заготовки, поэтому
дополнительных действий, связанных с этим подключением, выполнять не
требуется.
Вызов функции MPI_Initialized позволяет определить,
инициализирован для программы параллельный режим или нет. Если
режим инициализирован, то выходной параметр функции принимает
значение, отличное от нуля; в противном случае параметр полагается
равным нулю. Следует отметить, что инициализация параллельного
режима выполняется функцией MPI_Init, которая в приведенном коде
отсутствует. Это объясняется тем, что за инициализацию отвечает сам
задачник, и выполняется она перед тем, как программа переходит к
выполнению кода учащегося. Однако такая инициализация выполняется
задачником не всегда. Например, если программа запущена в демо-режиме
(для этого достаточно при вызове процедуры Task дополнить имя задания
символом «?»: Task("MPIBegin1?")), задачник не выполняет
инициализацию параллельного режима, поскольку в нем нет
необходимости. В этой ситуации вызов в коде учащегося функций MPI
(отличных от MPI_Initialized) может привести к некорректной работе
программы. Вызов функции MPI_Initialized и следующий за ним условный
оператор позволяют «пропустить» при выполнении
программы все операторы, введенные учащимся, если программа запущена
не в параллельном режиме.
Два последних оператора программы позволяют определить две
характеристики, необходимые для нормальной работы любого процесса
любой содержательной параллельной программы: общее количество
процессов (функция MPI_Comm_size) и ранг текущего процесса (функция
MPI_Comm_rank). Текущим считается процесс, вызвавший данную
функцию. Требуемая характеристика возвращается во втором (выходном)
параметре соответствующей функции; первым параметром является
коммуникатор, задающий набор процессов. Благодаря вызову этих
функций мы можем сразу использовать в нашей программе значения size
(общее число процессов в коммуникаторе MPI_COMM_WORLD) и rank
(ранг текущего процесса в коммуникаторе MPI_COMM_WORLD;
значение ранга обязательно лежит в диапазоне от 0 до
size 1). Обратите внимание на то, что в варианте для
языка C++ выходные параметры являются указателями на
соответствующие переменные, тогда как в варианте для Паскаля эти
параметры являются самими переменными, передаваемыми по ссылке (так
называемые var-параметры).
|