SynchroObject.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_SYNCHROOBJECT_H
00015 #define CNTM_SYNCHROOBJECT_H
00016 #include <Cntm/AsyncProc/Internal/ThreadProcFunctor.h>
00017 #include <Cntm/AsyncProc/Internal/DeferProcFunctor.h>
00018 #include <Cntm/Synchro/IBasicSynchro.h>
00019 #include <Cntm/Synchro/SynchroSpace.h>
00020 #include <Cntm/Synchro/ExtraSynchroSpace.h>
00021 
00022 namespace Cntm
00023 {
00024 
00025         class Sync;
00026         class ReentrantSync;
00027         
00028         /**
00029          * Базовый класс для синхрообъектов. Для того, чтобы создать свой класс синхрообъекта, его нужно унаследовать от классов Cntm::SynchroRefBase, Cntm::SynchroRefBaseEx или Cntm::SynchroAggregatedBase (эти объекты добавляют класс Cntm::SynchroObject как примесь к соответствующей реализации подсчета ссылок).
00030          * 
00031          * Синхрообъекты - это объекты со встроенными средствами синхронизации. Синхрообъект обязательно принадлежит определенному синхропространству (см. класс Cntm::SynchroSpace). Синхропространство задается при создании объекта и впоследствии не меняется.
00032          * 
00033          * Одна из важнейших функций синхрообъекта в многопоточных приложениях - эксклюзивный вход в синхропространство для выполнения действий, требующих синхронизации (т.е. они не должны быть прерваны другими действиями). Синхропространство в данном случае выступает как критическая секция или мьютекс, единая для всех объектов, принадлежащих синхропространству. Вход и выход из синхропространства выполняются методами Enter(), TryEnter() и Leave() или с помощью классов Cntm::Sync и Cntm::ReentrantSync (рекомендуется использовать классы, т.к. они повышают удобство и надежность). Вызов методов ...Enter() и Leave() аналогичен вызову соответствующих методов синхропространства. Процедуры входа в синхропространство рекурсивны. Принципы синхронизации описаны в классе Cntm::SynchroSpace.
00034          * 
00035          * Рекомендации по расположению точек входа в синхропространство. Если в системе используется только главное синхропространство и несколько потоков, то точки входа в синхропространство рекомендуется располагать в потоковых процедурах перед выполнением тех действий и вызовом тех методов, которые требуют синхронизации. Если в системе имеется несколько синхропространств, то вход в синхропространство рекомендуется делать в начале каждого интерфейсного метода (т.е. метода, который м.б. вызван из другого синхропространства), требующего синхронизации. Во внутренних методах (т.е. тех, которые непосредственно не вызываются из других синхропространств) делать точки входа в синхропространство не обязательно, т.к. эти методы вызываются уже из синхропространства. Пример:
00036          * \code
00037          * void Method1(int Arg)
00038          * {
00039          * Sync s(*this); // Точка входа в синхропространство до конца метода.
00040          * ...
00041          * }
00042          * \endcode
00043          * 
00044          * Дополнительно синхрообъект предоставляет методы для запуска асинхронных отложенных процедур (метод Defer()()) и асинхронных потоковых процедур (метод Thread()()). Асихронный означает, что поток выполнения не ожидает конца запущенной процедуры, а продолжает работу сразу же после запуска. Отложенная процедура - это  подготовленный вызов метода объекта (т.е. с указанием аргументов, которые будут переданы методу при вызове), который будет выполнен, когда будет возможен очередной вход в синхропространство. Асинхронные отложенные процедуры описаны в классе Cntm::AsyncProc. Реально отложенные процедуры реализованы через механизм отложенных синхрозаданий, описанный в документации по классу Cntm::SynchroSpace. Отложенные процедуры могут использоваться для синхронизированного вызова методов из разных потоков выполнения без входа в синхропространство. Асинхронная потоковая процедура - это метод объекта, который выполняется в отдельном потоке.  Потоковые процедуры также позволяют передавать любые аргументы в метод, который будет выполняться в отдельном потоке. Асинхронные потоковые процедуры описаны в классе Cntm::AsyncProc. Пример (асинхронный подсчет кол-ва слов в тексте):
00045          * \code
00046          * class Class1: public SynchroRefBase
00047          * {
00048          * int CalcWordsCount(const string& Text, const string& Delims) { ... return res; }
00049          * 
00050          * void Main()
00051          * {
00052          * string txt; cin >> txt;
00053          * AsyncProcResult<int> res = ThreadProc(&Class1::CalcWordsCount)(txt, " .,;:!?"); // Создание потока, выполняющего CalcWordsCount и передача ему текста txt и символов-разделителей.
00054          * ... // Выполнение каких либо полезных действий, например запись текста в файл.
00055          * cout << "Кол-во слов = " << res; // Вывод кол-ва слов на экран.
00056          * }
00057          * };
00058          * \endcode
00059          * 
00060          * При использовании синхрообъектов повышается удобство подключения к отложенным событиям (класс Cntm::DeferEvent) и вызов асинхронных отложенных процедур (методы Cntm::AsyncProc::Defer()()). Для работы этих средств требуется указание синхропространства, т.к. для синхрообъектов оно определено изначально, то нет нужды явно его указывать.
00061          * 
00062          * Синхронное создание объектов. Вызов конструктора синхрообъекта должен происходить внутри синхропространства, поэтому перед инициализацией объекта следует войти в то пространство, которому будет принадлежать объект. В качестве параметра конструктору передается синхропространство, к которому будет принадлежать объект. Имеется две формы конструкторов SynchroObject:
00063          * - первая форма явно принимает синхропространство. Она имеет вид: SynchroObject::SynchroObject(const SynchroSpace::Ptr& Space = SynchroSpace::Ptr()). Эта форма используется, когда операция создания синхрообъекта уже выполняется внутри пространства, к которому будет принадлежать новый объект. Если синхропространство не указано, то будет использовано главное синхропространство (т.о. если в программе используется только главное синхропространство, то нет необходимости указывать его явно). Если синхропространство явно не указано, а главное синхропространство отсутствует, то генерируется исключение Cntm::IllegalStateException.
00064          * - вторая форма принимает в качестве аргумента ссылку на объект синхросекции (классы Cntm::Sync или Cntm::ReentrantSync). Она имеет вид: SynchroObject::SynchroObject(Sync& ConstructSync) или SynchroObject::SynchroObject(ReentrantSync& ConstructSync). Эта форма используется, когда объект создается в новом или просто другом синхропространстве. В этом случае конструктор синхрообъекта пытается извлечь синхропространство из ConstructSync и если ConstructSync был проинициализирован, то использует извлеченное синхропространство. Если был указан пустой ConstructSync, то первым делом конструктор синхрообъекта создает дополнительное синхропространство (класс Cntm::ExtraSynchroSpace) и присваивает его ConstructSync (который передан по ссылке). Т.о. работа конструктора SynchroObject и конструкторов производных классов всегда будет осуществляться внутри синхпространства данного объекта.
00065          * 
00066          * Рекомендации по конструкторам пользовательских классов синхрообъектов. Если в системе используется только главное синхропространство, то никаких параметров использовать не нужно, объект автоматически будет принадлежать главному синхропространству. Если гарантируется, что объект будет создан внутри того синхропространства, к которому он будет принадлежать (обычно это внутренние объекты), то следует использовать только первую форму конструктора с явным указанием синхропространства. Если объект создается из произвольного синхропространства (в т.ч. из нового), то следует использовать вторую форму (возможно выбрав какую-то одну секцию, например, Sync). Если предполагается универсальное использование класса, то следует предоставить обе формы конструкторов (соответственно, три типа конструкторов). Примеры классов:
00067          * \code
00068          * // Класс, который создается в указанном синхропространстве.
00069          * class Class1: public SynchroRefBase
00070          * {
00071          * public:
00072          * typedef RefPtr<Class1> Ptr;
00073          * Class1(const SynchroSpace::Ptr& Space = SynchroSpace::Ptr()): SynchroRefBase(Space) {}
00074          * };
00075          * 
00076          * // Использование.
00077          * ...
00078          * Class1::Ptr c1 = new Class1; // Главное синхропространство.
00079          * ...
00080          * Class1::Ptr c2 = new Class1(this->Space()); // Явно указанное синхропространство, в него должен быть произведен вход перед использованием.
00081          * ...
00082          * 
00083          * // Класс, который создается в произвольном синхропространстве. Класс не использует реентерабельный вход, поэтому ограничимся только одной синхросекцией - Cntm::Sync.
00084          * class Class2: public SynchroRefBase
00085          * {
00086          * public:
00087          * typedef RefPtr<Class2> Ptr;
00088          * Class2(Sync& ConstructSync): SynchroRefBase(ConstructSync) {}
00089          * };
00090          * 
00091          * // Использование.
00092          * ...
00093          * Sync s;
00094          * Class2::Ptr c3 = new Class2(s); // Создает дополнительное синхрпространство, производит в него вход (заполняя s).
00095          * // На момент выхода из конструктора s будет содержать новое дополнительное синхропространство.
00096          * ...
00097          * Sync is(parent->Space()); // Войти в синхропространство.
00098          * Class2::Ptr c4 = new Class2(is); // Объект будет создан в синхропространстве parent->Space().
00099          * ...
00100          * \endcode
00101          * 
00102          * Синхронное уничтожение объектов. Подразумевает, что вызов деструкторов для классов Cntm::SynchroRefBase и Cntm::SynchroRefBaseEx и виртуального метода Cntm::SynchroRefBaseEx::OnReleaseInstance() будет производится отложенно синхронно по правилам для отложенных процедур или событий (см. выше) через механизм отложенных синхрозаданий (см. класс Cntm::SynchroSpace). Это значит, что вызов методов деинициализации будет происходить не в тот момент, когда будет утеряна последняя ссылка на объект, а когда можно будет осуществить отложенный синхронный вход в синхропространство, к которому принадлежал объект.
00103          * 
00104          * Данный класс обеспечивает многопоточность.
00105          * @author Овсеевич Р.
00106          * \ingroup Synchro
00107          */
00108         class SynchroObject: virtual public IBasicSynchro
00109         {
00110         public:
00111                 
00112                 typedef RefPtr<SynchroObject> Ptr;
00113 
00114                 /**
00115                  * Возвращает синхропространство, к которому принадлежит синхрообъект. Результат не может принять значение NULL. 
00116                  */
00117                 SynchroSpace::Ptr Space() const { return space; }
00118 
00119                 /**
00120                  * Возвращает текущий режим входа в синхропространство. Возвращает true, если вход во !все! синхропространства, в которых поток выполнения находится в данный момент, был произведен в реентерабельном режиме. Если был хотя бы один вход в нереентерабельном режиме, то возвращается false.
00121                  * 
00122                  * Метод должен вызываться только после входа в синхропространство и в том же потоке, который произвел вход.
00123                  * 
00124                  * Вызывает Space()->IsReentrantMode().
00125                  */
00126                 bool IsReentrantMode() const { return space->IsReentrantMode(); }
00127         
00128                 /**
00129                  * Возвращает текущий режим входа в синхропространство. Возвращает true, если вход во !все! синхропространства, в которых поток выполнения находится в данный момент, был произведен в реентерабельном режиме. Если был хотя бы один вход в нереентерабельном режиме, то возвращается false.
00130                  * 
00131                  * Метод должен вызываться только после входа в синхропространство и в том же потоке, который произвел вход.
00132                  * 
00133                  * Вызывает Space()->Enter().
00134                  * @param ReentrantMode - режим входа (реентерабельный или нет). Описание режимов входа приведено в описании класса Cntm::SynchroSpace.
00135                  */
00136                 void Enter(bool ReentrantMode = false) { space->Enter(ReentrantMode); }
00137         
00138                 /**
00139                  * Возвращает текущий режим входа в синхропространство. Возвращает true, если вход во !все! синхропространства, в которых поток выполнения находится в данный момент, был произведен в реентерабельном режиме. Если был хотя бы один вход в нереентерабельном режиме, то возвращается false.
00140                  * 
00141                  * Метод должен вызываться только после входа в синхропространство и в том же потоке, который произвел вход.
00142                  * 
00143                  * Вызывает Space()->TryEnter().
00144                  * @param ReentrantMode - режим входа (реентерабельный или нет). Описание режимов входа приведено в описании класса Cntm::SynchroSpace.
00145                  */
00146                 bool TryEnter(bool ReentrantMode = false) { return space->TryEnter(ReentrantMode); }
00147         
00148                 /**
00149                  * Производит выход из синхропространства. Парный метод для Enter() и TryEnter() (когда последний вернул true). Параметр ReentrantMode должен иметь такое же значение, как и у парного ему метода Enter() и TryEnter().
00150                  * 
00151                  * Более подробное описание режимов входа и случаев, когда вход в синхропространство выполняется из другого синхропространства приведенов в описании класса Cntm::SynchroSpace.
00152                  * 
00153                  * Вызывает Space()->Leave().
00154                  * @param ReentrantMode - режим входа (реентерабельный или нет). Описание режимов входа приведено в описании класса Cntm::SynchroSpace.
00155                  */
00156                 void Leave(bool ReentrantMode = false) { space->Leave(ReentrantMode); }
00157 
00158                 /**
00159                  * Запустить асинхронную потоковую процедуру. Первым параметром указывается адрес метода, 
00160                  * который будет выполнен в новом потоке. Описание остальных параметров, возвращаемого 
00161                  * значения и принципов работы приведено в описании класса Cntm::AsyncProc и метода 
00162                  * Cntm::AsyncProc::Thread()(). После вызова метода Thread() в скобках указываются 
00163                  * передаваемые потоковой функции аргументы. Thread(...) может рассматриваться как 
00164                  * идентификатор функции, а вторая пара скобок - как ее вызов.
00165                  * 
00166                  * Пример:
00167                  * \code
00168                  * Thread(&Class1::Thread1)(Arg1, Arg2);
00169                  * Thread(&Class1::Thread2)();
00170                  * \endcode
00171                  */
00172                 template < typename MethodSignatureT >
00173                 SpecUtils::ThreadProcFunctor < typename SignatureInfo < MethodSignatureT > ::FuncSign > Thread(
00174                         MethodSignatureT Method,
00175                         BasicAsyncProc::ThreadPriority Priority = BasicAsyncProc::tpNormal,
00176                         bool HoldRef = true)
00177                 {
00178                         return SpecUtils::ThreadProcFunctor<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00179                                 GenericMethodNoRefPtr<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00180                                 static_cast<typename SignatureInfo<MethodSignatureT>::ClassType*>(this), Method), Priority, HoldRef, false);
00181                 }
00182 
00183                 /**
00184                  * Запустить асинхронную отложеную процедуру. Первым параметром указывается адрес метода, 
00185                  * который будет выполнен в синхронно отложенно с использованием механизма отложенных 
00186                  * синхрозаданий (см. класс Cntm::SynchroSpace). Описание остальных параметров, 
00187                  * возвращаемого значения и принципов работы приведено в описании класса Cntm::AsyncProc
00188                  * и метода Cntm::AsyncProc::Defer()(). После вызова метода Defer() в скобках указываются 
00189                  * передаваемые отложенной функции аргументы. Defer(...) может рассматриваться как 
00190                  * идентификатор функции, а вторая пара скобок - как ее вызов.
00191                  * 
00192                  * Пример:
00193                  * \code
00194                  * Defer(&Class1::ShowMsg)(Arg1, Arg2);
00195                  * Defer(&Class1::Start)(); 
00196                  * \endcode
00197                  */
00198                 template < typename MethodSignatureT >
00199                 SpecUtils::DeferProcFunctor < typename SignatureInfo < MethodSignatureT > ::FuncSign > Defer(
00200                         MethodSignatureT Method,
00201                         bool HoldRef = true)
00202                 {
00203                         return SpecUtils::DeferProcFunctor<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00204                                 GenericMethodNoRefPtr<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00205                                 static_cast<typename SignatureInfo<MethodSignatureT>::ClassType*>(this), Method), Space(), HoldRef, false);
00206                 }
00207 
00208                 /**
00209                  * Создать отсроченную асинхронную потоковую процедуру. Первым параметром указывается 
00210                  * адрес метода, который будет выполнен в новом потоке. Описание остальных параметров, 
00211                  * возвращаемого значения и принципов работы приведено в описании класса Cntm::AsyncProc 
00212                  * и метода Cntm::AsyncProc::SuspendThread()(). После вызова метода SuspendThread() в 
00213                  * скобках указываются передаваемые потоковой функции аргументы. SuspendThread(...) может
00214                  * рассматриваться как идентификатор функции, а вторая пара скобок - как ее вызов.
00215                  * 
00216                  * Пример:
00217                  * \code
00218                  * SuspendThread(&Class1::Thread1)(Arg1, Arg2);
00219                  * SuspendThread(&Class1::Thread2)();
00220                  * \endcode
00221                  */
00222                 template < typename MethodSignatureT >
00223                 SpecUtils::ThreadProcFunctor < typename SignatureInfo < MethodSignatureT > ::FuncSign > SuspendThread(
00224                         MethodSignatureT Method,
00225                         BasicAsyncProc::ThreadPriority Priority = BasicAsyncProc::tpNormal,
00226                         bool HoldRef = true)
00227                 {
00228                         return SpecUtils::ThreadProcFunctor<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00229                                 GenericMethodNoRefPtr<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00230                                 static_cast<typename SignatureInfo<MethodSignatureT>::ClassType*>(this), Method), Priority, HoldRef, true);
00231                 }
00232 
00233                 /**
00234                  * Создать отсроченную асинхронную отложеную процедуру. Первым параметром указывается 
00235                  * адрес метода, который будет выполнен в синхронно отложенно с использованием механизма 
00236                  * отложенных синхрозаданий (см. класс Cntm::SynchroSpace). Описание остальных параметров, 
00237                  * возвращаемого значения и принципов работы приведено в описании класса Cntm::AsyncProc 
00238                  * и метода Cntm::AsyncProc::SuspendDefer()(). После вызова метода SuspendDefer() в скобках 
00239                  * указываются передаваемые отложенной функции аргументы. SuspendDefer(...) может 
00240                  * рассматриваться как идентификатор функции, а вторая пара скобок - как ее вызов.
00241                  * 
00242                  * Пример:
00243                  * \code
00244                  * SuspendDefer(&Class1::ShowMsg)(Arg1, Arg2);
00245                  * SuspendDefer(&Class1::Start)(); 
00246                  * \endcode
00247                  */
00248                 template < typename MethodSignatureT >
00249                 SpecUtils::DeferProcFunctor < typename SignatureInfo < MethodSignatureT > ::FuncSign > SuspendDefer(
00250                         MethodSignatureT Method,
00251                         bool HoldRef = true)
00252                 {
00253                         return SpecUtils::DeferProcFunctor<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00254                                 GenericMethodNoRefPtr<typename SignatureInfo<MethodSignatureT>::FuncSign>(
00255                                 static_cast<typename SignatureInfo<MethodSignatureT>::ClassType*>(this), Method), Space(), HoldRef, true);
00256                 }
00257 
00258         protected:
00259                 
00260                 /**
00261                  * Конструктор используется, когда операция создания синхрообъекта уже выполняется внутри пространства, к которому будет принадлежать новый объект. Если синхропространство не указано, то будет использовано главное синхропространство (т.о. если в программе используется только главное синхропространство, то нет необходимости указывать его явно).
00262                  * 
00263                  * @param Space - (опционально) используется для задания синхропространства, к которому будет принадлежать создаваемый объект.
00264                  * 
00265                  * Исключение Cntm::IllegalStateException - если синхропространство явно не указано, а главное синхропространство отсутствует
00266                  */
00267                 SynchroObject(const SynchroSpace::Ptr& Space = Cntm::SynchroSpace::Ptr());
00268                 
00269                 /**
00270                  * Конструктор используется, когда объект создается в новом или просто другом синхропространстве. В этом случае конструктор синхрообъекта пытается извлечь синхропространство из ConstructSync и если ConstructSync был проинициализирован, то использует извлеченное синхропространство. Если был указан пустой ConstructSync, то первым делом конструктор синхрообъекта создает дополнительное синхропространство (класс Cntm::ExtraSynchroSpace) и присваивает его ConstructSync (который передан по ссылке). Т.о. работа конструктора SynchroObject и конструкторов производных классов всегда будет осуществляться внутри синхпространства данного объекта.
00271                  * 
00272                  * @param ConstructSync - ссылка на синхросекцию, которая обеспечивает нахождение в синхропространстве при создании объекта.
00273                  */
00274                 SynchroObject(Sync& ConstructSync);
00275                 
00276                 /**
00277                  * Конструктор используется, когда объект создается в новом или просто другом синхропространстве. В этом случае конструктор синхрообъекта пытается извлечь синхропространство из ConstructSync и если ConstructSync был проинициализирован, то использует извлеченное синхропространство. Если был указан пустой ConstructSync, то первым делом конструктор синхрообъекта создает дополнительное синхропространство (класс Cntm::ExtraSynchroSpace) и присваивает его ConstructSync (который передан по ссылке). Т.о. работа конструктора SynchroObject и конструкторов производных классов всегда будет осуществляться внутри синхпространства данного объекта.
00278                  * 
00279                  * @param ConstructSync - ссылка на реентерабельную синхросекцию, которая обеспечивает нахождение в синхропространстве при создании объекта.
00280                  */
00281                 SynchroObject(ReentrantSync& ConstructSync);
00282                 
00283                 /**
00284                  * Деструктор. 
00285                  */
00286                 virtual ~SynchroObject() {}
00287 
00288         private:
00289 
00290                 friend class SynchroRefBase;
00291                 friend class SynchroRefBaseEx;
00292                 friend class SynchroDeleteTask;
00293                 
00294                 /**
00295                  * Класс синхрозадачи, которая выполняет операции деинициализации объекта. Ее выполнение состоит из вызова метода SynchroDeleteInstance удаляемого объекта.
00296                  * 
00297                  * Эта задача не реентерабельна.
00298                  * @author Овсеевич Р. 
00299                  */
00300                 class SynchroDeleteTask: public SynchroSpace::TaskBase
00301                 {
00302                 public:
00303 
00304                         /**
00305                          * Конструктор.
00306                          */
00307                         SynchroDeleteTask(SynchroObject* DeletedObject): deletedObject(DeletedObject) {}
00308 
00309                         /**
00310                          * Выполнить задачу. Вызывает метод SynchroDeleteInstance() удаляемого объекта.
00311                          */
00312                         void Exec(bool Recursive) { deletedObject->SynchroDeleteInstance(); }
00313 
00314                         /**
00315                          * Задача не рекурсивная.
00316                          */
00317                         bool IsRecursive() const { return false; }
00318                         
00319                 private:
00320 
00321                         /**
00322                          * Обычный указатель на удаляемую задачу.
00323                          */
00324                         SynchroObject* deletedObject;
00325                 };
00326 
00327                 
00328                 /**
00329                  * Ссылочный указатель на синхропространство, к которому принадлежит синхрообъект. Не может принять значение NULL. 
00330                  */
00331                 SynchroSpace::Ptr space;
00332 
00333                 /**
00334                  * Виртуальный метод, вызываемый синхронно отложенно, после того, как объект перешел в удаляемое состояние. Реализации вызывают метод DeleteInstance() классов Cntm::RefBase и Cntm::RefBaseEx. 
00335                  */
00336                 virtual void SynchroDeleteInstance() {}
00337 
00338                 /**
00339                  * Запустить синхронный отложенный вызов метода SynchroDeleteInstance() через механиз отложенных синхрозаданий. Вызывается в момент перехода в удаляемое состояние из методов DeleteInstance() реализаций. 
00340                  */
00341                 void CallSynchroDeleteInstance() { space->AddSynchroTask(new SynchroDeleteTask(this)); }                
00342         };
00343 
00344 }
00345 
00346 #endif //CNTM_SYNCHROOBJECT_H

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