- •Введение
- •Этапы большого пути
- •Библиотеки для параллельного и распределенного программирования
- •Новый единый стандарт спецификаций unix
- •Для кого написана эта книга
- •Среды разработки
- •Дополнительный материал Диаграммы uml
- •Профили программы
- •Параграфы
- •Тестирование кода и его надежность
- •Ждем ваших отзывов!
- •Благодарности
- •Преимущества параллельного программирования
- •Что такое параллелизм
- •Два основных подхода к достижению параллельности
- •Преимущества параллельного программирования
- •Простейшая модель параллельного программирования (pram)
- •Простейшая классификация схем параллелизма
- •Преимущества распределенного программирования
- •Простейшие модели распределенного программирования
- •Мультиагентные распределенные системы
- •Минимальные требования
- •Декомпозиция
- •Синхронизация
- •Базовые уровни программного параллелизма
- •Параллелизм на уровне инструкций
- •Параллелизм на уровне подпрограмм
- •Параллелизм на уровне объектов
- •Параллелизм на уровне приложений
- •Стандарт mpi
- •Pvm: стандарт для кластерного программирования
- •Стандарт corba
- •Реализации библиотек на основе стандартов
- •Среды для параллельного и распределенного программирования
- •Проблемы параллельного и распределенного программирования
- •Кардинальное изменение парадигмы
- •Проблемы координации
- •Проблема №3: взаимоблокировка
- •Проблема №4: трудности организации связи
- •Отказы оборудования и поведение по
- •Негативные последствия излишнего параллелизма и распределения
- •Выбор архитектуры
- •Различные методы тестирования и отладки
- •Связь между параллельным и распределенным проектами
- •Определение процесса
- •Два вида процессов
- •Блок управления процессами
- •Анатомия процесса
- •Состояния процессов
- •Планирование процессов
- •Стратегия планирования
- •Использование утилиты ps
- •Установка и получение приоритета процесса
- •Переключение контекста
- •Создание процесса
- •Отношения между родительскими и сыновними процессами
- •Утилита pstree
- •Использование системной функции fork()
- •Использование семейства системных функций exec
- •Функции execl ()
- •Функции execv ()
- •Определение ограничений для функций exec ()
- •Чтение и установка переменных среды
- •Использование posix-функций для порождения процессов
- •Идентификация родительских и сыновних процессов с помощью функций управления процессами
- •Завершение процесса
- •Ресурсы процессов
- •§ 3.1 • Граф распределения ресурсов ,
- •Типы ресурсов
- •Posix-функции для установки ограничений доступа к ресурсам
- •Асинхронные и синхронные процессы
- •Функция wait ()
- •Разбиение программы на задачи
- •Линии видимого контура
- •Определение потока
- •Контекстные требования потока
- •Сравнение потоков и процессов
- •Различия между потоками и процессами
- •Потоки, управляющие другими потоками
- •Преимущества использования потоков
- •Переключение контекста при низкой (ограниченной) доступности процессора
- •Возможности повышения производительности приложения
- •Простая схема взаимодействия между параллельно выполняющимися потоками
- •Упрощение структуры программы
- •Недостатки использования потоков
- •Потоки могут легко разрушить адресное пространство процесса
- •Один поток может ликвидировать целую программу
- •Потоки не могут многократно использоваться другими программами
- •Анатомия потока
- •Атрибуты потока
- •Планирование потоков
- •Состояния потоков
- •Планирование потоков и область конкуренции
- •Стратегия планирования и приоритет
- •Изменение приоритета потоков
- •Ресурсы потоков
- •Модели создания и функционирования потоков
- •Модель делегирования
- •Модель с равноправными узлами
- •Модель конвейера
- •Модель «изготовитель-потребитель»
- •Модели spmd и мрмd для потоков
- •Введение в библиотеку Pthread
- •Анатомия простой многопоточной программы
- •Компиляция и компоновка многопоточных программ
- •Создание потоков
- •Получение идентификатора потока
- •Присоединение потоков
- •Создание открепленных потоков
- •Использование объекта атрибутов
- •Создание открепленных потоков с помощью объекта атрибутов
- •Управление потоками
- •Завершение потоков
- •Точки аннулирования потоков
- •Очистка перед завершением
- •Управление стеком потока
- •Установка атрибутов планирования и свойств потоков
- •Установка области конкуренции потока
- •Использование функции sysconf ()
- •Управление критическими разделами
- •Безопасность использования потоков и библиотек
- •Разбиение программы на несколько потоков
- •Использование модели делегирования
- •Использование модели сети с равноправными узлами
- •Использование модели конвейера
- •Использование модели «изготовитель-потребитель»
- •Создание многопоточных объектов
- •Синхронизация параллельно выполняемых задач
- •Координация порядка выполнения потоков
- •Взаимоотношения между синхронизируемыми задачами
- •Отношения типа старт-старт (cc)
- •Отношения типа финиш-старт (фс)
- •Отношения типа старт-финиш (сф)
- •Отношения типа финиш-финиш (фф)
- •Синхронизация доступа к данным
- •Модель ррам
- •Параллельный и исключающий доступ к памяти
- •Что такое семафоры
- •Операции по управлению семафором
- •Мьютексные семафоры
- •Использование мьютексного атрибутного объекта
- •Использование мьютексных семафоров для управления критическими разделами
- •Блокировки для чтения и записи
- •Использование блокировок чтения-записи для реализации стратегии доступа
- •Условные переменные
- •Использование условных переменных для управления отношениями синхронизации
- •Объектно-ориентированный подход к синхронизации
- •Классические модели параллелизма, поддерживаемые системой pvm
- •Выполнение pvm-программы в виде двоичного файла
- •Запуск pvm-программ c помощью pvm-консоли
- •Запуск pvm-программ c помощью xpvm
- •Требования к pvm-программам
- •Методы использования pvm-задач
- •§ 6.1. Обозначение сочетаний
- •6.3. Базовые меха н измы pvm 233
- •Базовые механизмы pvm
- •Функции управления процессами
- •6.3. Базовые меха н измы pvm 235
- •Упаковка и отправка сообщений
- •6.3. Базовые механизмы pvm 237
- •Доступ к стандартному входному потоку (stdin) и стандартному выходному потоку (stdout) со стороны pvm-задач
- •Получение доступа к стандартному выходному потоку (cout) из сыновней задачи
- •Обработка ошибок, исключительных ситуаций и надежность программного обеспечения
- •Надежность программного обеспечения
- •Отказы в программных и аппаратных компонентах
- •Определение дефектов в зависимости от спецификаций по
- •Обработка ошибок или обработка исключительных ситуаций?
- •Надежность по: простой план
- •План а: модель возобновления, план б: модель завершения
- •Использование объектов отображения для обработки ошибок
- •Классы исключений
- •Классы runtime__error
- •Классы logic_error
- •Выведение новых классов исключений
- •Защита классов исключений от исключительныхситуаций
- •Диаграммы событий, логические выражения и логические схемы
- •Распределенное объектно-ориентированное программирование
- •Декомпозиция задачи и инкапсуляция ее решения
- •Взаимодействие между распределенными объектами
- •Синхронизация взаимодействия локальных и удаленных объектов
- •Обработка ошибок и исключений в распределенной среде
- •Доступ к объектам из других адресных пространств
- •Брокеры объектных запросов (orb)
- •Язык описания интерфейсов (idl):более «пристальный» взгляд на corba-объекты
- •Анатомия базовой corba-программы потребителя
- •Анатомия базовой corba-программы изготовителя
- •Базовый npoeкт corba-приложения
- •Получение ior-ссылки для удаленных объектов
- •Служба имен
- •§ 8.1. Семантические сети
- •Использование службы имен и создание именных контекстов
- •Служба имен «потребитель-клиент»
- •Подробнее об объектных адаптерах
- •Хранилища реализаций и интерфейсов
- •Простые pacnpeделенные Web-службы, использующие corba-спецификацию
- •Маклерская служба
- •Парадигма «клиент-сервер»
- •Реализация моделей spmd и mpmd с помощью шаблонов и mpi-программирования
- •Декомпозиция работ для mpi-интерфейса
- •Дифференциация задач по рангу
- •Группирование задач по коммуникаторам
- •Анатомия mpi-задачи
- •Использование шаблонных функций для представления mpi-задач
- •Реализация шаблонов и модельБрмо (типы данных)
- •Использование полиморфизмадля реализации mpmd-модели
- •Введение mpmd-модели c помощью функций -объектов
- •Как упростить взаимодействие между mpi-задачами
- •Визуализация проектов параллельных и распределенных систем
- •Визуализация структур
- •Классы и объекты
- •Отображение информации об атрибутах и операциях класса
- •Организация атрибутов и операций
- •Шаблонные классы
- •Отношения между классами и объектами
- •Интерфейсные классы
- •Организация интерактивных объектов
- •Отображение параллельного поведения
- •Сотрудничество объектов
- •Процессы и потоки
- •Отображение нескольких потоков выполнения и взаимодействия между ними
- •Последовательность передачи сообщений между объектами
- •Деятельность объектов
- •Конечные автоматы
- •Параллельные подсостояния
- •Распределенные объекты
- •Визуализация всей системы
- •Визуализация развертывания систем
- •Архитектура системы
- •Проектирование компонентов для поддержки параллелизма
- •Как воспользоваться преимуществами интерфейсных классов
- •Подробнее об объектно-ориентированном взаимном исключении и интерфейсных классах
- •«Полуширокие» интерфейсы
- •Поддержка потокового представления
- •Перегрузка операторов "«" и "»" для pvm-потоков данных
- •Пользовательские классы, создаваемые для обработки pvm-потоков данных
- •Объектно-ориентированные каналы и fifo-очереди как базовые элементы низкого уровня
- •Связь каналов c iostream-объектами с помощью дескрипторов файлов
- •18 Cerr « «Ошибка при создании канала " « endl;
- •Доступ к анонимным каналам c использованием итератора ostream_iterator
- •Fifo-очереди (именованные каналы),
- •Интерфейсные fifo-классы
- •Каркасные классы
- •Реализация агентно-ориентированных архитектур
- •Что такое агенты
- •Агенты: исходное определение
- •Типы агентов
- •В чем состоит разница между объектами и агентами
- •Понятие об агентно-ориентированном программировании
- •§ 12:1 Дедукция, индукция и абдукция
- •Роль агентов в распределенном программировании
- •Агенты и параллельное программирование
- •Базовые компоненты агентов
- •Когнитивные структуры данных
- •Методы рассуждений
- •Типы данных предположений и структуры убеждений
- •Класс агента
- •Цикл активизации агента
- •Простая автономность
- •12.6. Резюме
- •Реализация технологии «классной доски» с использованием pvm-средств, потоков и компонентов
- •Модель «классной доски»
- •Методы структурирования «классной доски»
- •Анатомия источника знаний
- •Стратегии управления для «классной доски»
- •Реализация модели «классной доски» с помощью corba-объектов
- •Пример использования corba-объекта «классной доски»
- •Реализация интерфейсного класса black_board
- •Порождение источников знаний в конструкторе «классной доски»
- •Порождение источников знаний с помощью pvm-задач
- •Связь «классной доски» и источников знаний
- •Активизация источников знаний с помощью posix-функции spawn()
- •Реализация модели «классной доски» с помощью глобальных объектов
- •Активизация источников знаний с помощью потоков
- •Приложение a
- •Диаграммы классов и объектов
- •Диаграммы сотрудничества
- •Диаграммы последовательностей
- •A.2.3. Диаграммы видов деятельности
- •A.3. Диаграммы состояний
- •A.4. Диаграммы пакетов
- •Приложение б 26
Введение mpmd-модели c помощью функций -объектов
Функции-объекты используются в стандартных алгоритмах для реализации горизонтального полиморфизма. Полиморфизм, реализованный с помощью передачи параметра vehicle *Transport в листинге 9.5, является вертикальным, поскольку для функционирования необходимо, чтобы классы были связаны наследованием. При горизонтальном полиморфизме классы связаны не наследованием, а интерфейсом. Все функции-объекты определяют операторную функцию operator (). Функции-объекты позволяют разрабатывать MPI-задачи с использованием некоторой общей формы.
// Функция-объект class some_class{ //.. .
operator(); //
};
template<class T> T mpiTask(T X) {
//
Т Result; Result = X() //. . .
}
Шаблонная функция mpiTask () будет работать с любым типом T, который имеет соответствующим образом определенную функцию operator ().
//. . .
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &TaskRank); MPI_Comm_size(MPI_COMM_WORLD, &WorldSize); //. . .
if(TaskRank == 0){ //. . .
user_defined_type M; mpiTask(M); //.. .
}
if(TaskRank == N){ //.. .
some_other_userdefined_type N; mpiTask (N) ;
}
//----
Этот горизонтальный полиморфизм не имеет отношения к наследованию или виртуальным функциям. Поэтому, если наша MPI-задача получит свой ранг, а затем объявит тип объекта, в котором определена функция operator (), то при вызове функции mpiTask () ее поведение будет продиктовано содержимым метода operator (). Тогда, несмотря на идентичность всех процессов, запу щ енных посредством сценария mpirun, полиморфизм шаблонов и функций-объектов позволит всем MPI-задачам выполнять различную работу над различными данными.
Как упростить взаимодействие между mpi-задачами
Помимо упрощения и сокращения размеров кода МРТзадачи с помощью полиморфизма и шаблонов, мы можем также упростить взаимодействие между MPI-задачами, воспользовавшись преимуществами перегрузки операторов. Функции MPI_Send () и MPI_Recv () имеют следующий формат:
MPI_Send(Buffer, Count, MPI_LONG, TaskRank, Tag, Comm);
MPI_Recv(Buffer,Count,MPI_INT, TaskRank, Tag, Comm, &Status);
При вызове этих функций необходимо, чтобы пользователь указал тип применяемых здесь данных и буфер, предназначенный для хранения посылаемых или принимаемых данных. Спецификация типа посылаемых или принимаемых данных может иметь довольно громоздкий вид и чревата последующими ошибками при передаче неверного типа. В табл. 9.3 приведены прототипы MPI-функций отправки и приема данных и их краткое описание.
Таблица 9.3 Прототипы MPI-функций отправки и приема данных
Функции Описание
#include «mpi.h»
int MPI_Send (void *Buffer,int Count, MPI_Datatype Туре, int Destination, int MessageTag, MPI_Comm Comm) ; Выполняет базовую отправку данных
int MPI_Send_init (void *Buffer,int Count, MPI_Datatype Type, int Destination, int MessageTag, MPI_Comm Comm, MPI_Request *Request); Инициализирует дескриптор для стандартной отправки данных
int MPI_Ssend (void *Buffer,int Count, MPI_Datatype Type, int Destination, int MessageTag, MPI_Comm Comm); Выполняет базовую отправку данных с синхронизацией
int MPI_Ssend_init (void *Buffer,int Count, MPI_Datatype Type, int Destination, int MessageTag, MPI_Comm Comm, MPI_Request *Request); Инициализирует дескриптор для стандартной отправки данных с синхронизацией
int MPI_Rsend (void *Buffer,int Count, MPI_Datatype Type, int Destination, int MessageTag, MPI_Comm Comm) ; Выполняет базовую отправкуданных с сигналом готовности
int MPI_Rsend_init (void *Buffer,int Count, MPI_Datatype Type, int Destination, int MessageTag, MPI_Comm Comm, MPI_Request *Request); Инициализирует дескриптор для стандартной отправки данных с сигналом готовности
int MPI_Isend (void *Buffer,int Count, MPI_Datatype Type, int Destination, int MessageTag, MPI_Comm Comm, MPI_Request *Request ); Запускает отправку без блокировки
int MPI_Issend (void *Buffer,int Count, MPI_Datatype Туре, int Destination, int MessageTag, MPI_Comm Comm, MPI_Request *Request); Запускает синхронную отправку без блокировки
int MPI_Irsend (void *Buffer,int Count, MPI_Datatype Туре, int Destination, int MessageTag, MPI_Comm Comm, MPI_Request *Request); Запускает неблокирующую отправкуданных с сигналом готовности
int MPI_Recv (void *Buffer,int Count, MPI__Datatype Type, int source, int MessageTag, MPI_Comm Comm, MPI_Status *Status); Выполняет базовый прием данных
int MPI_Recv_init (void *Buffer,int Count, MPI_Datatype Type, int source, int MessageTag, MPI_Comm Comm, MPI_Request *Request); Инициализирует дескриптор для приема данных
int MPI_Irecv (void *Buffer,int Count, MPI_Datatype Type, int source, int MessageTag, MPI_Comm Comm, MPI_Request *Request); Запускает прием данных без блокировки
int MPI_Sendrecv (void *sendBuffer, int SendCount, MPI_Datatype SendType, int Destination, int SendTag, void *recvBuffer, int RecvCount, MPI_Datatype RecvYype, int Source, int RecvTag, MPI_Comm Comm, MPI_Status *Status); Отправляет и принимает сообщение
int MPI_Sendrecv_replace (void *Buffer,int Count, MPI_Datatype Туре, int Destination, int SendTag,int Source,int RecvTag, MPI_Comm Comm, MPI_Status *Status); Отправляет и принимает сообщение с использованием единого буфера
Наша цель — обеспечить отправку и получение MPI-данных с помо щ ью потоково г о представления iostream-классов. Данные удобно отправлять, используя следую щ ий синтаксис.
//...
int X; float Y;
user_defined_type Z;
cout « X << Y « Z;
//...
Здесь разработчик не должен указывать типы данных при вставке их в объект cout. Для вывода этих данных трех типов достаточно определить оператор "<<". Анало г ично можно поступить при выделении данных из потоково г о объекта cin.
//...
int X; float Y;
user_defined_type Z;
cin >> X >> Y >> Z;
//...
В инструкции ввода данных их типы не задаются. Перегрузка операторов позволяет разработчику использовать этот метод для MPI-задач. Поток cout реализуется из класса ostream, а поток cin — из класса istream. В этих классах определены операторы "<<" и ">>" для встроенных С++-типов данных. Например, класс ostream содержит ряд перегруженных операторных функций "<<".
//.. .
ostream& operator<<(char с);
ostream& operator<<(unsigned char с);
ostream& operator<<(signed char с);
ostream& operator<<(const char *s);
ostream& operator<<(const unsigned char *s);
ostream& operator<<(const signed char *s);
ostream& operator<<(const void *p);
ostream& operator<<(int n);
ostream& operator<<(unsigned int n);
ostream& operator<<(long n);
ostream& operator<<(unsigned long n);
//.. .
С помощью этих определений пользователь классов ostream и istream применяет объекты cout и cin, не указывал типы передаваемых данных. Этот метод перегрузки можно использовать для упрощения МРI- взаимодействия. Мы рассмотрели идею PVM-потока в главе 6. Здесь мы применяем тот же подход к созданию MPI-потока, используя структуру классов istream и ostream в качестве руководства для разработки класса mpi_stream. Потоковые классы состоят из компонентов состояния, буфера и преобразования. Компонент состояния представлен классом ios; компонент буфера — классами streambuf, stringbuf или filebuf. Компонент преобразования обслуживается классами istream, ostream, istringstream, ostringstream, ifstream и ofstream. Компонент состояния отвечает за инкапсуляцию состояния потока. Класс ios включает формат потока, информацию о состоянии (работоспособное или состояние отказа), факт достижения конца файла (eof). Компонент буфера используется для хранения считываемых или записываемых данных. Классы преобразования предназначены для перевода данных встроенных типов в потоки байтов и обратно. UML-диаграмма семейства классов iostream показана на рис. 9.3.
Перегрузка операторов «<<» и «>>» для организации взаимодействия между MPI-задачами
Взаимоотношения и функциональность классов, показанных на рис. 9.3, можно использовать как своего рода образец для проектирования класса mpi_streams. И хотя проектирование потоковых MPI-классов требует больше предварительной работы по сравнению с непосредственны м использование м функций MPI_Recv () HMPI_Send() , в целом оно делает MPI-разработку значительно проще. А если программы с параллельной обработкой можно упростить, это нужно сделать обязательно. Уменьшение сложности программ — весьма достойнал цель для программиста. Здесь мы представляем лишь каркас класса mpi_stream. Но этого вполне достаточно для получения понятия о конструкции потокового MPI-класса. После разработки класса mpi_stream можно приступать к упрощению организации взаимодействия между MPI-задачами в большинстве MPI-программ. Листинг 9.6 содержит фрагмент из объявления класса mpi_stream.
// Листинг 9.6. Фрагмент объявления
// класса mpi_stream
class mpios{ protected:
int Rank;
int Tag;
MPI_Comm Comm;
MPI_Status Status;
int BufferCount;
//.- . public:
int tag(void);
//...
}
class mpi_stream public mpios{ protected:
mpi_buffer Buffer;
//.. .
public: //.. .
mpi_stream(void) ;
mpi_stream(int R,int T,MPI_Comm С);
void rank(int R);
void tag(int T);
void comm(MPI_Comm С);
mpi_stream &operator<<(int X);
mpi_stream &operator<<(float X);
mpi_stream &operator<<(string X);
mpi_stream &operator<<(vector<long> &X);
mpi_stream &operator<<(vector<int> &X),
mpi_stream &operator<<(vector<float> &X);
mpi_stream &operator<<(vector<string> &X);
mpi_stream &operator>>(int &X);
mpi_stream &operator>>(float &X);
mpi_stream &operator>>(string &X);
mpi_stream &operator>>(vector<long> &X);
mpi_stream &operator>>(vector<int> &X);
mpi_stream &operator>>(vector<float> &X);
mpi_stream &operator>>(vector<string> &X);
//. . .
};
Для того чтобы сократить описание, мы объединили классы impi _stream и ompi _stream в единый класс mpi _stream. И точно так же, как классы istream и ostream перегружают операторы "<<" и ">>", мы обеспечим их перегрузку в классе mpi_stream. В листинге 9.7 показано, как можно определить эти перегруженные операторы:
// Листинг 9.7. Определение операторов и **»*
//. . .
mpi_stream &operator<<(string X) {
MPI_Send(const_cast<char*>(X.data()),X.size(),
MPI__CHAR, Rank, Tag, Comm) ; return(*this);
}
// Упрощенное управление буфером, mpi_stream &operator<<(vector<long> &X) {
long *Buffer;
Buffer = new long[X.size()]; copy(X.begin(),X.end(),Buffer);
MPI_Send(Buffer,X.size(),MPI_LONG,Rank,Tag,Comm); delete Buffer; return(*this);
}
// Упрощенное управление буфером, mpi_stream &operator>>(string &X) {
char Buffer[10000];
MPI_Recv(Buffer,10000,MPI_CHAR,Rank,Tag,Comm, &Status); MPI_Get_count(&Status,MPI_CHAR,&BufferCount); X.append(Buffer); return(*this);
}
Назначение класса mpios в листинге 9.7 такое же, как у класса ios в семействе классов iostream, а именно: поддерживать состояние класса mpi_stream. Все типы данных, которые должны использоваться в ваших MPI-приложениях, должны иметь операторы "<<" и ">>", перегруженные с учетом каждого типа данных. Здесь мы продемонстрируем несколько простых перегруженных операторов. В каждом случае мы представляем упро щ енный вариант управления буфером. На практике необходимо прелусмотреть обработку исключений (на базе шаблонных классов) и распределение памяти (на базе классов-распределителей ресурсов). В листинге 9.7 обратите внимание на то, что класс mpios содержит коммуникатор, статус класса mpi_stream, номер буфера и значение ранга или тега (это — лишь одна из возможных конфигураций класса mpi_stream— существует множество других). После того как класс mpi_stream определен, его можно использовать в любой MPI-программе. Взаимодействие между MPI-задачами может быть организовано следую щ им образом.
//. . .
int X; float Y;
vector<float> Z;
mpi_s tream S tream (Rank, Tag, MPI_WORLD_COMM) ;
Stream « X << Z; Stream << Y;
//...
Stream >> Z;
Такой подход позволяет программисту, поддерживал потоковое пре д ставление, упростить МРТко д. Безусловно, в опре д еление операторов "<<" и ">>" необходимо включить соответствующую проверку ошибок и обработку исключительных ситуаций.
Резюме
Реализация SPMD- и MPMD-моделей параллелизма во многом выигрывает от использования шаблонов и механизма полиморфизма. Несмотря на то что MPT интерфейс включает средства динамического С++-связывания, в нем не используются преимущества методов объектно-ориентированного программирования. Это создает определенные трудности для разработчиков, использующих стандарт MPI. Для упрощения MPMD-программирования можно успешно использовать такие свойства объ-ектноориентированного программирования, как наследование и полиморфизм. Параметризованное программирование, которое поддерживается с помощью C++-шаблонов, позволяет упростить SPMD-программирование MPI-задач. Разделение работы программы между объектами — это естественный способ реализовать параллелизм в приложении. Для того чтобы облегчить взаимодействие между группами объектов, характеризующимися различной степенью ответственности за выполняемую работу, семейства объектов в MPI-приложении можно связать с коммуникаторами. Для поддержки потокового представления используется перегрузка операторов. Применение методов объектно-ориентированного и параметризованного программирования в рамках одного и того же MPI-приложения является воплощением муль-типарадигматического подхода, который упрощает код и во многих случалх уменьшает его объем. Тем самым упрощается отладка программ, их тестирование и поддержка. МРТзадачи, реализованные с помощью шаблонных функций, характеризуются более высокой надежностью при использовании различных типов данных, чем отдельно определенные функции с последующим обязательным выполнением операции приведения типа.