class synchronization_variable{
protected:
runtime_error Exception;
//.. .
public:
int virtual lock(void) = 0;
int virtual unlock(void) = 0;
int virtual trylock(void) = 0;
//.. .
}
;
Обратите внимание на то, что методы синхронизации класса synchronization_variable объявлены виртуальными и инициализированы значением 0. Это означает, что они являются чисто виртуальными методами, что делает класс
// Листинг 11.8. Объявление класса мьютекс, который
// наследует класс synchronization_variable
class mutex : public synchronization_variable {
protected:
pthread_mutex_t *Mutex;
pthread_mutexattr_t *MutexAttr;
//.. .
public:
int lock(void) ;
int unlock(void);
int trylock(void);
//. . .
};
Класс mutex должен обеспечить реализации для всех чисто виртуальных функций. Если эти функции определены, значит, политика, предложеннал абстрактным классом, выдержана. Класс mutex теперь не является абстрактным, поэтому из него и из его потомков можно создавать объекты. Каждый из методов класса mutex заключает в оболочку соответствующую Pthread-функцию. Например, код
int mutex::trylock(void) {
//.. .
return(pthread_mutex_trylock(Mutex); //. . .
}
обеспечивает интерфейс для функции pthread_mutex_trylock(). Интерфейсные варианты функций lock(), unlock() и trylock() упрощают вызовы функций библиотеки Pthread. Наша цель — использовать инкапсуляцию и наследование для определения всего семейства мьютексных классов. Процесс наследования — это процесс специализации. Производный класс включает дополнительные атрибуты или характеристики, которые отличают его от предков. Каждый атрибут или характеристика, добавленная в производный класс, конкретизирует его. Теперь мы, используя наследование, можем спроектировать специализацию класса mutex путем введения понятия мьютексного класса, способного обеспечить чтение и запись. Наш обобщенный класс mutex предназначен для защиты доступа к критическому разделу. Если один поток заблокировал мьютекс, он получает доступ к критическому разделу, защищаемому этим мьютексом. Иногда такая мера предосторожности оказывается излишне суровой. Возможны ситуации, когда вполне можно разрешить доступ нескольких потоков к одним и тем же данным, если ни один из этих потоков не модифицирует данные. Другими словами, в некоторых случаях мы можем ослабить блокировку критического раздела и «намертво» запирать его только для действий, которые стремятся модифицировать данные, разрешал при этом доступ для действий, которые предполагают лишь считывание или копирование данных. Такой вид блокировки называется