Академический Документы
Профессиональный Документы
Культура Документы
Параллельное программирование
Для эффективного использования высокопроизводительных вычислительных систем
необходимо уметь их эффективно программировать. Одного языка программирования, пусть
даже самого современного, уже не достаточно для программирования многопроцессорных
или многомашинных комплексов, если они должны выполнять одну программу. Необходимо
программировать и обмены данными между процессами одной задачи, выполняющимися на
разных процессорах. Кроме того, возникнут вопросы контроля правильности обмена, взаим-
ной синхронизации процессов, отладки и верификации. Таким образом, мы приходим к по-
нятию параллельной программы, программы, которая состоит из нескольких программ, в
общем случае содержащих различный код, и которая решает одну задачу.
Для создания параллельных программ разработано и продолжает разрабатываться
множество языков и технологий параллельного программирования. Назовем лишь несколь-
ко: Ada, ATLAS, HPF, HPC, Linda, Modula-3, MPI, mpC, OpenMP, Occam, P4, Parallaxis, PVM
и др. В процессе создания языков параллельного программирования выработано несколько
подходов к организации распараллеливания программ. Рассмотрим некоторые. Наиболее
простой и известный подход связан с построением системы параллельного программирова-
ния на основе существующего языка для программирования последовательной машины. На-
пример язык HPF – High Perfomance Fortran. В нем использована очень привлекательная идея
включения в программу "подсказок" для компилятора в виде комментариев. Как известно,
комментарий в языке Fortran обозначается символом C. Операторы организации параллель-
ных вычислений, например обмена, обозначаются в HPF с помощью двух символов C. Таким
образом, программу можно компилировать и с помощью обычного компилятора: все что
начинается с символа C является для него комментарием, а для компилятора, снабженного
средствами распараллеливания, операторы, начинающиеся с двойного CC являются операто-
рами для компиляции параллельных операторов.
Другой подход – включение в обычный язык программирования специальных функций
из специально созданных для параллельного программирования библиотек. Мы рассмотрим
несколько наиболее популярных технологий параллельного программирования.
Для программирования компьютеров с разделяемой памятью, т.е. SMP-компьютеров
используется система OpenMP. Это стандарт, разработанный для языков Fortran, C, C++ и
многих операционных платформ UNIX, Linux, Windows NT. Вся программа разбивается на
последовательные и параллельные участки. Последовательные участки реализуются основ-
ным потоком или нитью (thread), а параллельные – дочерними потоками. Все переменные
разделяются на общие и локальные, причем, локальные переменные являются доступными
только внутри конкретного потока, а общие - доступны для всех потоков. Понятно, что под-
ход многопоточности очень удобен для систем с разделяемой памятью. Области для парал-
лельного выполнения выделяются с помощью директив, начало которых обозначаются с по-
мощью символа комментария, о которых говорилось выше. Например:
C$OMP PARALLEL
код для параллельного выполнения
C$OMP END PARALLEL
Внутри параллельного блока порождается столько потоков, сколько указал программист пе-
ред запуском программы. В конце параллельного блока все потоки синхронизируются, т.е.
происходит ожидание завершения работы всех потоков и их уничтожение. Число потоков
внутри потоков можно изменять с помощью специальных операторов. Кроме того, сущест-
вует множество различных операторов для управления работой потоков и выполнения
различных коллективных операций. Для более подробного ознакомления с технологией
OpenMP можно рекомендовать сайт http://www.openmp.org. В настоящее время эта техноло-
2
Среди множества функций библиотеки стандарта MPI можно выделить несколько ос-
новных функций, с помощью которых организуется работа параллельной программы.
Одной из первых функций в программе должна быть функция инициализация библио-
теки MPI MPI_Init(&argc,&argv), которая получает адреса аргументов от функции
main(), которая, в свою очередь, получает из операционной системы. Эти аргументы хранят
параметры командной строки. После вызова функции становятся доступными другие функ-
ции библиотеки MPI.
Для завершения работы параллельной программы используется функция
MPI_Finalize(), после которой уже нельзя использовать функции библиотеки MPI.
Для организации работы программы часто необходимо бывает знать число процессов
или процессоров задействованных внутри коммуникатора и номер данного процесса. Для
этого используются функции:
MPI_Comm_size(comm,&size);
MPI_Comm_rank(comm,&rank);
где void *buf - адрес буфера, т.е. начальный адрес буфера приёма (передачи). Каждый
процесс имеет собственный наборы данных и собственный буфер приема (передачи), поэто-
му адреса буферов каждого из процессов отличаются друг от друга;
int count - размер буфера в количестве ячеек (не в байтах) типа datatype. Для функции
передачи MPI_Send() указывается, сколько ячеек требуется передать, а для функции приема
MPI_Recv() - максимальная емкость приемного буфера. Если фактическая длина пришед-
шего сообщения меньше - последние ячейки буфера не заполняются, если больше - произой-
дет ошибка времени выполнения;
MPI_Datatype datatype - тип ячеек буфера. Функции MPI_Send() и MPI_Recv() опери-
руют массивами однотипных данных. Для описания базовых типов языка С в MPI определе-
ны константы MPI_INT, MPI_CHAR, MPI_DOUBLE и др., имеющие тип MPI_Datatype. Их
названия образуются префиксом MPI_ и именем соответствующего типа (int, char,
double, ...), записанным заглавными буквами. Пользователь может зарегистрировать (опре-
делить) в MPI-приложении свои собственные типы данных, например структуры, после чего
функции MPI смогут обрабатывать их также как и базовые типы;
int dest (source) - номер процесса приемника (источника), с которым происходит обмен
данными;
int tag - идентификатор сообщения, с помощью которого одно сообщение отличается от
другого. Идентификатор сообщения - это целое число от 0 до 32767, которое назначается
пользователем. Важно, чтобы отправленное сообщение с назначенным номером, было при-
нято с таким же номером;
MPI_Comm comm - описатель области связи (коммуникатор);
MPI_Status *status - статус завершения приема. По адресу status содержится инфор-
мация о принятом сообщении, в частности, его идентификатор, номер процесса-передатчика,
код завершения и количество фактически принятых данных.
Пользуясь рассмотренными функциями, напишем простейшую параллельную про-
грамму, которая передает сообщение в виде строки символов из одного процесса в другой.
#include <stdio.h>
#include <string.h>
#include "mpi.h"