- •Введение
- •Этапы большого пути
- •Библиотеки для параллельного и распределенного программирования
- •Новый единый стандарт спецификаций 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
Разбиение программы на несколько потоков
Выше в этой главе мы рассматривали делегирование работы в соответствии с конкретной стратегией или потоковой моделью. Итак, используются следующие распространенные модели:
• делегирование («управляющий-рабочий»");
• сеть с равноправными узлами;
• конвейер;
• «изготовитель-потребитель».
Каждая модель характеризуется собственной декомпозицией работ (Work Breakdown Structure — WBS), которая определяет, кто отвечает за создание потоков и при каких условиях они создаются. В этом разделе мы рассмотрим пример программы для каж дой модели, использующей функции библиотеки Pthread.
Использование модели делегирования
Мы рассмотрели два подхода к реализации модели делегирования при разделении мы на потоки. Вспомним: в модели делегирования один поток (управляющий) создает другие потоки (рабочие) и назначает каждому из них задачу. Управляющий поток делегирует каждому рабочему потоку задачу, которую он должен выполнить, путем задания некоторой функции. При одном подходе управляющий поток создает рабочие потоки как результат запросов, обращенных к системе. Управляющий поток обрабатывает запрос каждого типа в цикле событий. Как только событие произойдет, будет создан рабочий поток и ему будет назначена задача. Функционирование цикла событий в управляющем потоке и создание рабочих потоков продемонстрировано в листинге 4 .5.
// Листинг 4.5. Подход 1: скелет программы реализации II модели управляющего и рабочих потоков
//...
pthread_mutex_t Mutex = PTHREAD_MUTEX_INITIALIZER
int AvailableThreads
pthread_t Thread[Max_Threads]
void decrementThreadAvailability(void)
void incrementThreadAvailability(void)
int threadAvailability(void);
// boss thread
{
//...
if(sysconf(_SC_THREAD_THREADS_MAX) > 0){
AvailableThreads = sysconf(_SC_THREAD_THREADS_MAX)
}
else{
AvailableThreads = Default
}
int Count = 1;
loop while(Request Queue is not empty)
if(threadAvailability()){
Count++
decrementThreadAvailability()
classify request
switch(request type)
{
case X : pthread_create(&(Thread[Count])...taskX...)
case Y : pthread_create(&(Thread[Count])...taskY...)
case Z : pthread_create(&(Thread[Count])...taskZ...)
//...
}
}
else{
//free up thread resources
}
end loop
}
void *taskX(void *X)
{
// process X type request
incrementThreadAvailability()
return(NULL)
}
void *taskY(void *Y)
{
// process Y type request
incrementThreadAvailability()
return(NULL)
}
void *taskZ(void *Z)
{
// process Z type request
decrementThreadAvailability()
return(NULL)
}
В листинге 4.5 управляющий поток динамически создает поток для обработки каждого нового запроса, который поступает в систему. Однако существует ограничение на количество потоков (максимальное число потоков), которое можно создать в процессе. Для обработки n типов запросов существует n задач. Чтобы гарантировать, что максимальное число потоков на процесс не будет превышено, определяются следующие дополнительные функции:
threadAvailability()
incrementThreadAvailability()
decrementThreadAvailability()
В листинге 4.6 содержится псевдокод реализации этих функций.
// Листинг 4.6. Функции, которые управляют возможностью
// создания потоков
void incrementThreadAvailability(void)
{
//...
pthread_mutex_lock(&Mutex)
AvailableThreads++
pthread_mutex_unlock(&Mutex)
}
void decrementThreadAvailability(void)
{
//...
pthread_mutex_lock(&Mutex)
AvailableThreads—
pthread_mutex_unlock(&Mutex)
}
int threadAvailability(void)
{
//...
pthread_mutex_lock(&Mutex)
if(AvailableThreads > 1)
return 1
else
return 0
pthread_mutex_unlock(&Mutex)
}
Ф ункция threadAvailability() возвратит число 1, если максимально допустимое количество потоков для процесса еще не достигнуто. Эта функция опрашивает глобальную переменную ThreadAvailability, в которой хранится число потоков, еще доступных для процесса. Управляющий поток вызывает функцию decrementThreadAvailability(), которая декрементирует эту глобальную переменную до создания им рабочего потока. Каждый рабочий поток вызывает функцию incrementThreadAvailability(), которая инкрементирует глобальную переменную ThreadAvailability до начала его выполнения. Обе функции содержат обращение к функции pthread_mutex_lock () до получения доступа к этой глобальной переменной и обращение к функции pthread_mutex_unlock() после него. Если максимально допустимое количество потоков превышено, управляющий поток может отменить создание потока, если это возможно, или породить другой процесс, если это необходимо. Функции taskX(), taskY () и taskZ () выполняют код, предназначенный для обработки запроса соответствующего типа.
Другой подход к реализации модели делегирования состоит в создании управляющим потоком пула потоков, которым (вместо создания под каждый новый запрос нового потока) переназначаются новые запросы. Управляющий поток во время инициализации создает некоторое количество потоков, а затем каждый созданный поток приостанавливается до тех пор, пока в очередь не будет добавлен новый запрос. Управляющий поток для выделения запросов из очереди по-прежнему использует цикл событий. Но вместо создания нового потока для обслуживания очередного запроса, управляющий поток уведомляет уже существующий поток о необходимости обработки запроса. Этот подход к реализации модели делегирования представлен в листинге 4.7.
// Листинг 4.7. Подход 2: скелет программы реализации . модели управляющего и рабочих потоков
pthread_t Thread[N]
// boss thread
{
pthread_create(&(Thread[1]...taskX...);
pthread_create(&(Thread[2]...taskY...);
pthread_create(&(Thread[3]...taskZ...);
//...
loop while(Request Queue is not empty
get request
classify request
switch(request type)
{
case X :
enqueue request to XQueue
signal Thread[1]
case Y :
enqueue request to YQueue
signal Thread[2]
case Z :
enqueue request to ZQueue
signal Thread[3]
//...
}
end loop
}
void *taskX(void *X)
{
loop
suspend until awaken by boss
loop while XQueue is not empty
dequeue request
process request
end loop
until done
{
void *taskY(void *Y)
{
loop
suspend until awaken by boss
loop while YQueue is not empty
dequeue request
process request
end loop
until done
}
void *taskZ(void *Z)
{
loop
suspend until awaken by boss
loop while (ZQueue is not empty)
dequeue request
process request
end loop
until done
}//.. .
В листинге 4.7 управляющий поток создает N рабочих потоков (по одному для каждого типа задачи). Каждая задача связана с обработкой запросов некоторого типа В цикле событий управляющий поток извлекает запрос из очереди запросов, определяет его тип, ставит его в очередь запросов, соответствующую типу, а затем оправляет сигнал потоку, который обрабатывает запросы из этой очереди. Функции потоков также содержат циклы событий. Поток приостанавливается до тех пор, пока не получит сигнал от управляющего потока о существовании запроса в его очереди. После «пробуждения» (уже во внутреннем цикле) поток обрабатывает все запросы до тех пор, пока его очередь не опустеет.