Программирование >>  Синтаксис инициирования исключений 

1 ... 42 43 44 [ 45 ] 46 47 48 ... 82


private:

SafeSet<Lock>* locks;

void AddLock(Lock*); Включить блокировку в транзакцию

public:

~Transaction();

void Commit(); Закрепить все образы

void Ro11back(); Отменить все образы

bool OwnsLock(Lock*); Истина, если блокировка

принадлежит транзакции

Класс Transaction поддерживает коллекцию блокировок с помощью гипотетического шаблона Collection. Функция RegisterLock() включена в базовый класс Lock и потому может обратиться к закрытой функции AddLock() класса Transaction. Дружба не наследуется, поэтому объявление другом класса Lock не делает друзьями его производные классы. Реализации выглядят довольно просто.

void Transaction::AddLock(Lock* lock)

*1ocks += lock; Использует перегрузку += для коллекции

void Transaction::Commit()

SafeSetIterator<Lock>* iter = 1ocks->Iterator(); while (iter->More())

iter->Next()->Commit(); delete iter;

void Transaction::Ro11back()

SafeSetIterator<Lock>* iter = 1ocks->Iterator(); while (iter->More())

iter->Next()->Ro11back(); delete iter;

bool Transaction::OwnsLock(Lock* lock)

return *1ocks >= lock;

Предполагается, что шаблон Collection содержит функцию De1eteAl1() для удаления всех объектов; что перегруженный оператор += (операторная функция operator+=(Type*) ) включает элемент в коллекцию; что перегруженный оператор >= определяет принадлежность к коллекции, а функция Iterator() возвращает вложенный итератор. Это обобщенные условия; используйте те, которые действуют в вашем случае.

Класс ConstPtr

Классы, производные от Lock, должны ссылаться на нечто близкое к указателям, доступным только для чтения, с которыми на страницах книги вы уже познакомились.

template <c1ass Type>

class LockPtr; Ссылка вперед на класс, производный от Lock



template <c1ass Type>

class ConstPtr {

friend class LockPtr<Type>;

private:

Type* o1d image; Образ перед транзакцией

LockPtr<Type>* lock; Текущая блокировка, если она есть

~ConstPtr() { delete o1d image; }

ConstPtr<Type>& operator=(const ConstPtr<Type>& cp)

{ return *this; } Присваивание не разрешается

public:

ConstPtr() : o1d image(NULL), lock(NULL) {} ConstPtr(const ConstPtr<Type>& cp)

: o1d image(new Type(*(cp.o1d image))), lock(NULL) {} const Type* operator->() const { return o1d image; } LockPtr<Type>& Lock(Transaction* t);

template <c1ass Type>

LockPtr<Type>& ConstPtr<Type>::Lock(Transaction* t)

if (lock != NULL && !t->OwnsLock(1ock))

Конфликт - уже имеется другой владелец else {

lock = new LockPtr<Type>(t, this); return *1ock;

Новый объект ConstPtr можно сконструировать на базе старого (хотя новый создается без блокировки), однако нам придется внести изменения для присваивания, которое разрешено только для LockPtr , но не для ConstPtr . Для этой цели мы определяем фиктивный оператор = и делаем его закрытым, чтобы до него никто не добрался. Поскольку указатель является ведущим, его удаление приводит и к удалению указываемого объекта (самое радикальное изменение, которое только можно представить). По этой причине конструктор также объявлен закрытым, чтобы никто не попытался удалить ConstPtr .

Конфликт в функции Lock можно обработать разными способами:

Инициировать исключение.

Изменить интерфейс и возвращать вместе с блокировкой флаг, показывающий, успешно ли прошла блокировка.

Возвращать LockPtr<Type>* со значением NULL, свидетельствующем о неудачной блокировке.

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

Предоставить отдельную функцию CanLock(Transaction*) , которая возвращает логическое значение.

Выбор зависит от стиля. Вариант с исключением не так уж очевиден; неудача при блокировке представляет собой вполне разумный исход.



Класс LockPtr

Ага! Мы подошли к центральной идее всей концепции - указателям, которые разрешают обновление указываемого объекта. Предтранзакционный (предназначенный для отмены) образ хранится в ConstPtr, а текущий обновленный образ доступен только через LockPtr. Класс LockPtr содержит уже знакомые функции Ro11back() и Commit(). В функции Snapshot() нет необходимости, поскольку LockPtr при необходимости создает образы в операторе ->.

template <c1ass Type> class LockPtr : public Lock { friend class ConstPtr<Type>; private:

ConstPtr<Type>* master ptr;

Type* new image;

Transaction* transaction;

LockPtr(Transaction* t, ConstPtr<Type>* cp); virtual ~LockPtr(); virtual void Ro11back(); virtual void Commit(); public:

Type* operator->() const { return new image; }

template <c1ass Type>

LockPtr<Type>::LockPtr(Transaction* t, ConstPtr<Type>* cp)

: transaction(t), master ptr(cp), new image(new Type(*(cp->o1d image)))

template <c1ass Type> LockPtr<Type>::~LockPtr()

В сущности происходит откат

delete new image; Отказаться от изменений

master ptr->1ock = NULL; Оставить ConstPtr

template <c1ass Type>

void LockPtr<Type>::Ro11back()

delete new image;

new image = new Type(*(master ptr->o1d image));

template <c1ass Type>

void LockPtr<Type>::Commit()

delete master ptr->o1d image;

master ptr->o1d image = new image; Переместить в master ptr new image = new Type(*new image); Нужна новая копия

Деструктор объявлен закрытым, чтобы никто не мог напрямую удалить LockPtr. Вместо этого транзакция-владелец должна сделать это через базовый класс Lock. Функции Ro11back() и Commit () объявлены виртуальными, чтобы с их помощью можно было решать задачи, относящиеся к



1 ... 42 43 44 [ 45 ] 46 47 48 ... 82

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика