Камерон Хьюз - Параллельное и распределенное программирование на С++
- Название:Параллельное и распределенное программирование на С++
- Автор:
- Жанр:
- Издательство:Издательский дом «Вильямс»
- Год:2004
- Город:МоскваСанкт-ПетербургКиев
- ISBN:ISBN 5-8459-0686-5 (рус.)ISBN 0-13-101376-9 (англ.)
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Камерон Хьюз - Параллельное и распределенное программирование на С++ краткое содержание
Эта книга адресована программистам, проектировщикам и разработчикам программных продуктов, а также научным работникам, преподавателям и студентам, которых интересует введение в параллельное и распределенное программирование с использованием языка С++.
Параллельное и распределенное программирование на С++ - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
mpi_stream Stream1;
mpi_stream Stream2;
Streaml << Messagel << Message2 << Message3;
Stream2 >> Message4;
//. . .
Нри таком подходе программист может целиком сосредоточиться на логике программы и не ломать голову над соблюдением требований к синтаксису библиотеки MPI.
Как воспользоваться преимуществами интерфейсных классов
Зачастую полезно использовать инкапсуляцию, чтобы скрыть детали библиотек функций и обеспечить создание самодостаточных компонентов, которые годятся для многократного использования. Возьмем для примера мьютекс, который мы рассматривали в главе 7. Вспомним, что мьютекс— это переменная специального типа, ис-пользуемая для синхронизации. Мьютексы позволяют получать безопасный доступ к критическом) разделу данных или кода программы. Существует шесть основных функций, предназначенных для работы с переменной типа pthread_mutex_t (POSIX Threads Mutex).
Все эти функции принимают в качестве параметра указатель на переменную типа pthread_mutex_t. Для инкапсуляции доступа к переменной типа pthread_mutex_t и упрощения вызовов функций, которые обращаются к мьютексным переменным, можно использовать интерфейсный класс. Рассмотрим листинг 11.1, в котором объявляется класс mutex.
// Листинг 11.1. Объявление класса mutex
class mutex{ protected:
pthread_mutex_t *Mutex;
pthread_mutexattr_t *Attr; public:
mutex(void)
int lock(void);
int unlock(void);
int trylock(void);
int timedlock(void);
};
Объявив класс mutex,используем его для определения мьютексных пере м енных. Мы можем объявлять массивы мьютексов и использовать эти пере м енные как члены пользовательских классов. Инкапсулировав пере м енную типа • pthread_mutex_tи мьютексные функции, воспользуемся преимуществами методов объектно-ориентированного программирования. Эти мьютексные переменные можно затем применять в качестве аргументов функций и значений, возвра щ аемых функциями. А поскольку мьютексные функции теперь связаны с переменной типа pthread_mutex_t,то там, где мы используем мьютексную переменную, эти функции также будут доступны.
Функции-члены класса mutexопределяются путем заключения в оболочку вызовов соответствующих Pthread-функций, например, так.
// Листинг 11.2. Функции-члены класса mutex
mutex::mutex(void) {
try{
int Value;
Value = pthread_mutexattr_int(Attr); //. . .
Value = pthread_mutex_init(Mutex,Attr); //. . .
\
}
int mutex::lock(void) {
int RetValue;
RetValue = pthread_mutex_lock(Mutex); //. . .
return(ReturnValue);
}
Благодаря инкапсуляции мы также защищаем переменные типа pthread_mutex_t* и pthread_mutexattr_t*. Другими словами, при вызове методов lock(), unlock(), trylock()и других нам не нужно беспокоиться о том, к каким мьютексным переменным или переменным атрибутов будут применены эти функции. Возможность скрывать информацию (посредством инкапсуляции) позволяет программисту писать вполне безопасный код. С помощью свободно распространяемых версий Рthread-функций этим функциям можно передать любую переменную типа pthread_mutex_t.Однако при передаче одной из этих функций неверно заданного мьютекса может возникнуть взаимоблокировка или отсрочка бесконечной длины. Инкапсуляция переменных типа pthread_mutex_tи pthread_mutexattr_tв к л ассе mutexпредостав л яет программисту полный контроль над тем, какие функции получат доступ к этим переменным.
Теперь мы можем использовать такой встроенный интерфейсный класс, как mutex,в любых других пользовательских классах, предназначенных для безопасной обработки потоков выполнения. Предположим, мы хотели бы создать очередь с многопоточной поддержкой и многопоточный класс pvm_stream.Очередь будем использовать для хранения поступающих событий для множества потоков, образованных в программе. На некоторые потоки возложена ответственность за отправку сообщений различным PVM-задачам. PVM-задачи и потоки выполняются параллельно. Несколько потоков выполнения разделяют единственный PVM-класс и единственную очередь событий. Отношения между потоками, PVM-задачами, очередью событий и классом pvm_streamпоказаны на рис. 11.1.
Очередь, показанная на рис. 11.1, представляет собой критический раздел, поскольку она совместно используется несколькими выполняемыми потоками. Класс pvm_stream— это также критический раздел и по той же причине. Если эти критические разделы не синхронизировать и не защитить, то данные в очереди и классе pvm_streamмогут разрушиться. Тот факт, что несколько потоков могут одновременно обновлять либо очередь, либо код класса pvm_stream,открывает среду для «гонок». Чтобы не допустить этого, мы должны обеспечить нашу очередь и к л асс pvm_streamвстроенны м и средства м и блокировки и разблокировки. Эти средства также поддерживаются классом mutex.На рис. 11.2 показана диаграмма классов для наших пользовательских классов x_queueи pvm_stream.
Обратите внимание на то, что класс x_queueсодержит к л асс мьютекс, т.е. между классами x_queueи мьютекс существует отношение агрегирования. Любая операция, которая изменяет состояние наше г о к л асса x_queue,может привести к «гонкам» данных, если, конечно, эгу операцию не синхронизировать. Следовательно, операции, которые добавляют объект в очередь или удаляют его из нее, являются кандидатами для синхронизации. В листинге 11.3 приведено объявление к л асса x_queueкак шаблонного.
Рис.11.1. Отношения между потоками, PVM-задачами, очередью событий и классом pvm_stream в PVM-программе |
Рис.11.2. Диаграмма классов для пользовательских классов x_queue и pvm_stream |
// Листинг 11.3. Объявление класса x_queue
template x_queue class{
protected:
queue EventQ;
mutex Mutex;
//...
public:
bool enqueue(T Object);
T dequeue(void);
//...
};
Метод enqueue()используется для добавления элементов в очередь, а метод dequeue()— для удаления их из очереди. Каждый из этих методов рассчитан на использование oбъeктaMutex. Определение этих методов приведено в листинге 11.4.
// Листинг 11.4. Определение методов enqueue() и dequeue()
tempIate bool x_queue::enqueue(T Object)
{
Mutex.lock(); EventQ.push(Object); Mutex.unlock();
}
Leinplr.te T x_queue::dequeue(void)
{
T Object; //. . .
Mutex.lock();
Object = EventQ.front()
EventQ.pop();
Mutex.unlock() ;
//. . .
return(Object);
}
Теперь очередь может функционировать (принимать новые элементы и избавляться от ненужных) в многопоточной среде. ПотокВ (см. рис.11.1) добавляет элементы в очередь, а потокА удаляет их оттуда. Класс mutex является интерфейсным классом. Он заключает в оболочку функции pthread_mutex_lock (), pthread_mutex_unlock (), pthread_mutex_init() и pthread_mutex_trylock(). Класс x_queue также является интерфейсным, поскольку он адаптирует интерфейс для встроенного класса queue . Прежде всего, он заменяет интерфейсы методов push() и pop() методами enqueue() и dequeue() . При этом операции вставки и удаления элементов из очереди заключаются между вызовами методов Mutex.lock() и Mutex.unlock(). Поэтому в первом случае мы используем интерфейсный класс для инкапсуляции переменных типа pthread_mutex_t* и pthread_mutexattr_t*, а также заключаем в интерфейсную оболочку несколько функций из библиотеки Pthread. А во втором случае мы используем интерфейсный класс для адаптации интерфейса класса queue. Еще одно достоинство класса mutex состоит в том, что его легко использовать в других классах, которые содержат критические разделы или области.
Читать дальшеИнтервал:
Закладка: