RefBaseEx.h

См. документацию.
00001 /*
00002  * CntmLib - Подсчет ссылок, потоки, синхронизация, асинхронные процедуры, события
00003  * Copyright (c) 2005, Овсеевич Роман, CntmLib@mail.ru
00004  * _______________________________________________________________________________
00005  * Разрешено свободное использование, копирование, распространение, изменение
00006  * (изменение сведений об авторских правах запрещено). Запрещена продажа и 
00007  * включение всей библиотеки или ее частей в другие библиотеки. В сведениях об
00008  * авторских правах на программу (или сведениях о программе, об авторах, 
00009  * использованных средствах разработки и т.д.) должна быть указана информация
00010  * о библиотеке CntmLib, ее авторе и, возможно, сайте или email'е.
00011  * Библиотека поставляется "как есть", без каких-либо гарантий со стороны автора.
00012  */ 
00013 
00014 #ifndef CNTM_REFBASEEX_H
00015 #define CNTM_REFBASEEX_H
00016 #include <boost/limits.hpp>
00017 #include <Cntm/SystemUtils/AtomicUtils.h>
00018 #include <Cntm/Exceptions/IllegalStateException.h>
00019 #include <Cntm/Exceptions/NullArgException.h>
00020 #include <Cntm/RefCount/RefObjectUsedException.h>
00021 #include <Cntm/RefCount/ForceDeleteRefObjectException.h>
00022 #include <Cntm/RefCount/RefBase.h>
00023 
00024 namespace Cntm
00025 {
00026 
00027     /**
00028          * Более сложная реализация подсчета ссылок. Применяется в особых случаях, когда возможностей RefBase недостаточно. Кроме функциональности RefBase он обеспечивает расширенные средства по деинициализации объекта при уничтожении ссылок на него. Применяется в качестве базового класса или примеси для пользовательских классов, которые управляются подсчетом ссылок.
00029          * 
00030          * Особенности использования класса RefBaseEx в том, что он позволяет использовать ссылочные указатели в деструкторе и производить отложенное уничтожение.
00031          * 
00032          * Данный класс содержит виртуальный метод OnReleaseInstance(), который вызывается перед деструктором когда ссылок на объект не осталось и он переходит в удаляемое состояние. Этот метод может использоваться для запуска длительной асинхронной операции деинициализации объекта, например, в другом потоке. Чтобы обрабатывать это событие пользовательские классы должны переопределить этот метод. Реализация метода в RefBaseEx не выполняет ни каких действий.
00033          * 
00034          * Выше упоминалось, что при исчезновении ссылок на объект он переводится в удаляемое состояние, в котором подсчет ссылок не работает (см. IRefObject). В отличие от RefBase RefBaseEx позволяет вернуть объект из удаляемого состояние в рабочее, по сути дела начать новый цикл использования объекта. Для этого служит метод ReanimateInstance(). Данному методу передается ссылочный указатель, который инициализируется указателем на данный объект, после завершения метода кол-во ссылок устанавливается в 1 и появляется возможность использовать ссылочные указатели на данный объект. Когда все вновь созданные ссылки на данный будут утеряны, объект вновь перейдет в удаляемое состояние. Второй аргумент данного метода влияет на то, будет ли вызван метод OnReleaseInstance() при повторном переходе в удаляемое состояние (по умолчанию не будет).
00035          * 
00036          * Рассмотрим несколько сценариев использования:
00037          * 
00038          * 1. Использование ссылочных указателей в деструкторе. Для этого в деструкторе следует вызвать ReanimateInstance(), передав ему принимающий указатель, который после завершения метода будет указывать на данный объект. Второй аргумент функции не используется. После этого можно использовать ссылочные указатели на данный объект. Особенности данного сценария:
00039          * - когда счетчик ссылок достигнет 0, OnReleaseInstance вызываться не будет;
00040          * - после выхода из деструктора пользовательского класса ссылок на объект оставаться не должно. В противном случае для сигнализации о такой ошибке в деструкторе RefBaseEx будет сгенерировано исключение RefObjectUsedException для сигнализации о серьезной ошибке, которое будет автоматически перехвачено библиотекой.
00041          * 
00042          * 2. Отложенное уничтожение. Для этого следует переопределить метод OnReleaseInstance() и в нем вызвать ReanimateInstance(), передав первым параметром указатель, который будет указывать на данный объект, а вторым - флаг нужно ли вызывать OnReleaseInstance в следующий раз (если ничего не указывать, то вызова не будет). После этого можно передать указатель другим объектам для операций деинициализации или запустить поток, выполняющий эти действия. В последнем случае следует сохранять ссылочный указатель. Это можно обеспечить либо передачей указателя потоку как параметра или использовать поле класса. Перед завершением работы поток должен уничтожить или сбросить указатель в NULL. Особенности данного сценария:
00043          * - запрещается вручную удалять объект из метода OnReleaseInstance;
00044          * - когда счетчик ссылок повторно достигнет 0, будет опять вызван метод OnReleaseInstance() (если это явно указано при предыдущем вызове). Этот вызов может придти, когда первый OnReleaseInstance еще не завершил работу (например, если полученный указатель будет уничтожен в самом OnReleaseInstance() или фоновый поток закончит работу раньше, чем завершится первый OnReleaseInstance()).
00045          * - в случае повторных вызовов OnReleaseInstance() библиотека гарантирует, что деструктор объекта будет вызван после завершения работы всех вызывов OnReleaseInstance, даже если они вложены или выполняются параллельно.
00046          * 
00047          * Объекты классов, использующих RefBaseEx, должны размещаться только в динамической памяти, т.к. их поведение сильно связано с подсчетом ссылок, кроме того, принудительное удаление таких объектов запрещено (в деструкторе RefBaseEx будет сгенерировано исключение ForceDeleteRefObjectException, которое будет автоматически перехвачено библиотекой, сигнализирующее о неправильном использовании объекта).
00048          * 
00049          * Еще одно назначение класса RefBaseEx - блокировка завершения программы при наличие объектов, унаследованных от RefBaseEx. Более подробное описание этой возможности приведено в документации по методу WaitDestroyAll.
00050          * 
00051          * Данный класс обеспечивает многопоточность.
00052          * @author Овсеевич Р.
00053          * \ingroup RefCount
00054          */
00055         class RefBaseEx: public RefBase
00056         {
00057         public:
00058 
00059                 /**
00060                  * Ожидание разрушения всех объектов, унаследованных от RefBaseEx, в течении MSecTimeout мсек. Если задержка не указана, то ожидание будет длиться бесконечно.
00061                  *
00062                  * Результат: true - все объекты уничтожились, false - некоторые объекты остались неуничтоженными.
00063                  * 
00064                  * Функцией можно пользоваться одновременно из нескольких потоков.
00065                  */
00066                 static inline bool WaitDestroyAll(uint MSecTimeout = std::numeric_limits<uint>::max())
00067                 {
00068                         return SpecUtils::RefObjectImplUtils::WaitDestroyAll(MSecTimeout);
00069                 }       
00070         
00071         protected:
00072 
00073                 /**
00074                  * Конструктор. Производит инициализацию объекта, устанавливает кол-во ссылок в 0. 
00075                  */
00076                 RefBaseEx(): RefBase(), reanimateCounter(1), enableOnReleaseNotify(true)
00077                 {
00078                         // Сообщаем о создании нового объекта с подсчетом ссылок
00079                         // для обеспечения ожидания уничтожения всех таких объектов.
00080                         SpecUtils::RefObjectImplUtils::IncRefObjectCount(this);
00081                 }
00082 
00083                 /**
00084                  * Виртуальный деструктор. Выполняет ряд проверочных действий.
00085                  * 
00086                  * Исключения:
00087                  * RefObjectUsedException - когда на объект еще имеются ссылки.
00088                  * ForceDeleteRefObjectException - когда произошла попытка принудительного удаления объекта.
00089                  * Эти исключения обрабатываются самой библиотекой и служат отладочным целям. 
00090                  */
00091                 ~RefBaseEx()
00092                 {
00093                         try
00094                         {
00095                                 // Сообщаем об уничтожении объекта с подсчетом ссылок.
00096                                 SpecUtils::RefObjectImplUtils::DecRefObjectCount(this);
00097 
00098                                 // Попытка удалить объект вручную. В нормальном состоянии 
00099                                 // reanimateCounter должен равняться 1 (перед деструктором 0 + 1).
00100                                 if (!reanimateCounter.DecAndTest())
00101                                         throw ForceDeleteRefObjectException("Cntm::RefBaseEx::~RefBaseEx");
00102                         }
00103                         catch (...)
00104                         {
00105                         }
00106                 }
00107 
00108                 /**
00109                  * Перевести объект из удаляемого состояния, в которое он переходит при уничтожении всех ссылок на него, в рабочее. После вызова этого метода счетчик ссылок устанавливается в 1, становятся вновь доступны ссылочные указатели на данный объект. Если объект не в удаляемом состоянии, то производится установка RepeatOnRelease и возвращается ссылочный указатель.
00110                  * 
00111                  * Данный метод должен вызываться только из переопределенного виртуального метода OnReleaseInstance() или деструктора.
00112                  * 
00113                  * Параметры:
00114                  * Первый параметр этой функции - Dest - адрес ссылочного указателя, который принимает новый указатель на данный объект. Он не должен равняться NULL. Тип Dest является аргументом шаблона (ReanimateInstance - шаблонная функция), поэтому к нему выдвигается такое требование: он должен быть адресом ссылочного указателя на класс данного объекта или класс предка.
00115                  * Второй аргумент - RepeatOnRelease - разрешает или запрещает вызов метода OnReleaseInstance() при следующем переходе объекта в удаляемое состояние. Если он равен false, то будет сразу вызван деструктор, если true, сначала вызовется OnReleaseInstance(). По умолчанию параметр равен false.
00116                  * 
00117                  * Исключения:
00118                  * NullArgException - если первый параметр Dest равен NULL.
00119                  * BadArgException - если тип Dest'а не является типом ссылочного указателя на класс данного объекта или на класс его предка.
00120                  */
00121                 template < typename T >
00122                 void ReanimateInstance(RefPtr < T > * Dest, bool RepeatOnRelease = false)
00123                 {
00124                         // Получающий указатель должен быть задан обязательно.
00125                         if (Dest == NULL) 
00126                                 throw NullArgException("Cntm::RefBaseEx::ReanimateInstance", 
00127                                         "Указатель обязательно должен быть задан");
00128 
00129                         // Если объект в удаляемом состоянии, то реинициализируем кол-во 
00130                         // ссылок.
00131                         ReinitReferenceCounter();
00132                         *Dest = dynamic_cast<T*>(this);
00133                         
00134                         // Устанавливаем флаг повторных вызовов OnDeleteInstance(), увеличиваем 
00135                         // счетчик кол-ва текущих жизненных циклов.
00136                         enableOnReleaseNotify = enableOnReleaseNotify && RepeatOnRelease;                       
00137                         reanimateCounter.Inc();
00138                 }
00139 
00140                 /**
00141                  * Данный виртуальный метод вызывается когда объект переходит в удаляемое состояние, если его вызов не был запрещен в предыдущем вызове данного метода с помощью ReanimateInstance. Для обработки этого события пользовательский класс может переопределить метод.
00142                  * 
00143                  * Реализация этого метода для RefBaseEx не выполняет ни каких действий.
00144                  * 
00145                  * Все исключения, сгенерированные в переопределнном методе, будут проигнорированы. 
00146                  */
00147                 virtual void OnReleaseInstance() {}
00148 
00149                 /**
00150                  * Метод обработки события уничтожения последней ссылки на данный объект. Он позволяет либо запустить фоновый процесс уничтожения с длительными действиями, либо уничтожить объект.
00151                  * 
00152                  * Без крайней необходимости этот метод переопределять не рекомендуется.
00153                  */
00154                 void DeleteInstance();
00155 
00156         private:
00157 
00158                 /**
00159                  * Счетчик кол-ва текущих жизненных циклов.
00160                  */
00161                 SpecUtils::AtomicVariable reanimateCounter;
00162                 
00163                 /**
00164                  * Разрешен ли вызов метода оповещения о возможности уничтожить объект.
00165                  */
00166                 bool enableOnReleaseNotify;
00167         };
00168 
00169 }
00170 
00171 #endif //CNTM_REFBASEEX_H

SourceForge.net Logo
© Овсеевич Р.В. Документация по CntmLib 1.1.4 от 28 May 2008. Создано системой  doxygen 1.5.3