Выполнение задания MPIBegin1
Перейдем к выполнению задания. Теперь, когда мы
подробно познакомились с механизмом работы программы в параллельном
режиме, решение этой простой задачи не будет представлять для нас
особых проблем.
Начнем с ввода исходных данных. По условию в каждом процессе
дано по одному целому числу. Перейдем на пустую строку,
расположенную ниже вызова функции MPI_Comm_rank. Если при
выполнении программы будет достигнут данный участок кода,
следовательно, программа была запущена как один из процессов
параллельного приложения (в противном случае был бы выполнен
оператор выхода, указанный в условном операторе). Значит, в этом месте
программы можно ввести элемент исходных данных, предварительно
описав его (здесь и далее в варианте для языка С++ будем
приводить для краткости только функцию Solve):
[C++]
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);
int n;
pt >> n;
}
[Pascal]
program MPIBegin1;
uses PT4, MPI;
var
flag, size, rank: integer;
n: 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);
GetN(n);
end.
Для ввода исходных данных мы используем стандартные для
задачника Programming Taskbook операции: процедуру GetN для Pascal и
поток ввода pt для C++ (вместо процедуры GetN можно было бы использовать «универсальную» процедуру Get).
Запустив полученную программу, мы увидим на экране окно задачника:
Задачник обнаружил, что ввод данных выполнен, и, таким образом,
программа приступила к решению задачи. Однако ни один
результирующий элемент данных не был выведен, поэтому на информационной панели
окна задачника появилось сообщение об ошибке
«Выведены не все результирующие данные. Ошибка произошла в
процессах 14». Главный процесс (процесс ранга 0)
в сообщении не упоминается, так как в случае, если ошибки ввода-вывода
обнаружены в одном или нескольких подчиненных процессах, задачник не
анализирует состояние главного процесса.
Если запуск программы не является ознакомительным, то в окне задачника
отображается панель индикаторов. Первые два индикатора показывают число
введенных и выведенных элементов данных, третий индикатор показывает общий прогресс
выполнения задания. Если все требуемые исходные данные введены, то над индикатором
ввода дополнительно выводится зеленый маркер; если выведено требуемое количество
результирующих данных, то зеленый маркер выводится и над индикатором вывода.
В случае обнаружения ошибок ввода-вывода над соответствующим индикатором выводится
маркер, цвет которого соответствует типу выявленной ошибки (в нашем случае
выявлена ошибка, связанная с выводом недостаточного количества результирующих данных;
этому типу ошибки соответствует индикатор оранжевого цвета). Этот же цвет используется
и в качестве фонового цвета для информационной панели, если на ней выводится
оообщение об ошибке.
Если ошибки обнаружены в подчиненных процессах, в окне задачника
отображается дополнительный раздел отладки, в котором для
каждого подчиненного процесса выводится более подробная информация
об ошибке.
Определить, с каким процессом связано то или иное
сообщение, выведенное в разделе отладки,
можно по номеру, указываемому в левой части строки (перед
символом «|»). Все строки, связанные с определенным
процессом, нумеруются независимо от остальных строк; их номера
указываются после номера процесса и отделяются от текста сообщения
символом «>». Для того чтобы отобразить в разделе
отладки только сообщения, связанные с каким-либо одним процессом,
достаточно щелкнуть мышью на метке с номером (рангом) этого
процесса (метки размещаются в левом нижнем углу раздела отладки)
или нажать соответствующую цифровую клавишу. Для отображения
сводной информации по всем процессам надо щелкнуть на метке с символом «*»
или ввести этот символ с клавиатуры
(отметим, что перебирать метки можно также с помощью клавиш со стрелками [Left] и
[Right]). Если строка сообщения в разделе отладки начинается с символа
«!», то это означает, что данное сообщение является
сообщением об ошибке и добавлено в раздел отладки самим
задачником. Программа учащегося может выводить в раздел отладки свои
собственные сообщения; об этой возможности будет подробно рассказано
далее.
Итак, ни в одном процессе не выведены результирующие данные (в
этом можно убедиться и по виду области результатов: кроме комментариев
в ней ничего не указано).
Добавим после оператора ввода соответствующий оператор вывода, в
котором выведем удвоенное значение исходного значения n:
[C++]
pt << 2 * n;
[Pascal]
PutN(2 * n);
Запуск исправленного варианта приведет к появлению окна с другим
сообщением об ошибке:
Теперь во всех подчиненных процессах выведены требуемые
результаты. Кроме того, удвоенное число выведено и в главном процессе.
Однако в главном процессе требовалось также вывести количество
процессов, входящих в коммуникатор, а это сделано не было. Поэтому в
данном случае на информационной панели указано, что ошибка произошла
в главном процессе (процессе ранга 0).
Количество процессов хранится в переменной size. Попытаемся
вывести ее значение в конце нашей программы:
[C++]
pt << size;
[Pascal]
PutN(size);
Окно задачника примет следующий вид:
Можно убедиться в том, что все результирующие данные выведены.
Однако решение по-прежнему считается ошибочным, поскольку теперь мы
попытались вывести лишние данные (а именно значение size) в
подчиненных процессах. Как обычно, при обнаружении ошибок в
подчиненных процессах дополнительная информация об этих ошибках выводится в
разделе отладки.
В данном случае сообщение об ошибке выводится на малиновом фоне, и
этот же цвет имеет маркер, указанный над индикатором вывода. Малиновый цвет
используется в случае ошибок, связанных с вводом или выводом избыточного количества
данных.
Для того чтобы значение size было выведено только в главном
процессе, необходимо перед выполнением этого действия убедиться, что
ранг текущего процесса равен 0. Добавив соответствующую проверку, мы
получим, наконец, правильное решение:
[C++]
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);
int n;
pt >> n;
pt << 2 * n;
if (rank == 0)
pt << size;
}
[Pascal]
program MPIBegin1;
uses PT4, MPI;
var
flag, size, rank: integer;
n: 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);
GetN(n);
PutN(2 * n);
if rank = 0 then
PutN(size);
end.
Начиная с версии 4.13, задачник автоматически выполняет многократный
запуск учебной программы, пока не будет выявлена какая-либо ошибка или пока не будет
успешно пройдено требуемое число тестов. Для заданий группы MPIBegin
требуется успешно пройти пять тестовых запусков, после чего
на экране появится окно задачника с сообщением «Задание
выполнено!»:
|