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 <class T> x_queue class{

protected:

queue<T> EventQ;

mutex Mutex;

//...

public:

bool enqueue(T Object);

T dequeue(void);

//...

};

Метод enqueue() используется для добавления элементов в очередь, а метод dequeue() — для удаления их из очереди. Каждый из этих методов рассчитан на использование oбъeктaMutex. Определение этих методов приведено в листинге 11.4.

// Листинг 11.4. Определение методов enqueue() и dequeue()

tempIate<class T> bool x_queue<T>::enqueue(T Object)

{

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату