просто, захотелось его продолжить, интересно же :)) ...
заведем базовый класс:
typedef struct tagBaseSynchPtr{ CRITICAL_SECTION cs; // простой вход в критическую секцию VOID Enter( VOID ){ ::EnterCriticalSection( &cs ); } // простой выход из критической секции VOID Leave( VOID ){ ::LeaveCriticalSection( &cs ); } tagBaseSynchPtr( VOID ){ ::InitializeCriticalSection( &cs ); } ~tagBaseSynchPtr( VOID ){ ::DeleteCriticalSection( &cs ); } private: // запрет на копирование, чтобы даже соблазна не возникало tagBaseSynchPtr&operator = ( const tagBaseSynchPtr&Src ){ UNREFERENCED_PARAMETER( Src ); return*this; } }BASESYNCHPTR,*PBASESYNCHPTR;теперь опишем на его основе синхронизатор "по ссылке":
template< typename Object > class SynchPtr : public tagBaseSynchPtr{ protected: Object* pObject; public: // прокси - объект-ссылка, собственно и реализующий сериализацию class Proxy{ protected: SynchPtr< Object >* pPtr; public: Proxy( SynchPtr< Object >*pPtr = NULL ) : pPtr( pPtr ){ if( pPtr ){ pPtr->Enter(); } } // добавлен копирующий конструктор Proxy( const typename SynchPtr< Object >::Proxy&Src ): pPtr( Src.pPtr ){ if( pPtr ){ pPtr->Enter(); } } // конструкторы и деструктор не случайно используют NULL, // таким образом, можно принудительно выйти // из критической секции в любой момент, если нужно ~Proxy( VOID ){ if( pPtr ){ pPtr->Leave(); } } Object*operator -> ( VOID ){ return pPtr->pObject; } // добавлен константный доступ const Object*operator -> ( VOID )const{ return pPtr->pObject; } // добавлен оператор присваивания, т.е. прокси-указатели // можно спокойно использовать по старинке: обрамляя // синхронизаторами блоки кода, который невозможно // или затруднительно представить атомарным вызовом Proxy&operator = ( const Proxy&Src ){ if( pPtr ){ pPtr->Leave(); } pPtr = Src.pPtr; if( pPtr ){ pPtr->Enter(); } return*this; } }; typename SynchPtr< Object >::Proxy operator->( VOID ){ return this; } SynchPtr< Object >( Object*pObject ) : pObject( pObject ){} ~SynchPtr< Object >( VOID ){} SynchPtr< Object >&operator = ( Object*pObject ){ this->pObject = pObject; return*this; } private: // аналогичный запрет на копирование SynchPtr< Object >&operator = ( const SynchPtr< Object >&Src ){ UNREFERENCED_PARAMETER( Src ); return*this; } };теперь опишем синхронизатор "относительно базы", такой SafePtr требуется, когда проксируемый объект может в моменты синхронизации менять свой базовый адрес, например: из параллельного потока
template< typename Object, typename Owner > class RelSynchPtr : public tagBaseSynchPtr{ protected: // RelSynchPtr объект требует 2 поля (см. далее) Owner RelSynchPtr< Object, Owner >::*pOwner; Object Owner::*pObject; public: class Proxy{ protected: RelSynchPtr< Object, Owner >* pPtr; public: Proxy( RelSynchPtr< Object, Owner >*pPtr = NULL ): pPtr( pPtr ){ if( pPtr ){ pPtr->Enter(); } } Proxy( const Proxy&Src ) : pPtr( Src.pPtr ){ if( pPtr ){ pPtr->Enter(); } } ~Proxy( VOID ){ if( pPtr ){ pPtr->Leave(); } } operator Object*( VOID ){ return &(( pPtr->*( pPtr->pOwner )).*( pPtr->pObject )); } Object*operator -> ( VOID ){ return &(( pPtr->*( pPtr->pOwner )).*( pPtr->pObject )); } const Object*operator -> ( VOID )const{ return &(( pPtr->*( pPtr->pOwner )).*( pPtr->pObject )); } Proxy&operator = ( const Proxy&Src ){ if( pPtr ){ pPtr->Leave(); } pPtr = Src.pPtr; if( pPtr ){ pPtr->Enter(); } return*this; } }; typename RelSynchPtr< Object, Owner >::Proxy operator->( VOID ){ return this; } // для инициализации такого объекта требуется 2 поля: // - поле RelSynchPtr // - поле самого объекта // оба поля должны находиться в пределах одного класса Owner, // в таком случае экземпляр Owner может менять базу в любой момент RelSynchPtr< Object, Owner >( RelSynchPtr< Object, Owner > Owner::*pThis, Object Owner::*pObject ) : pOwner( ::reverse_field( pThis ) ), pObject( pObject ){} ~RelSynchPtr< Object, Owner >( VOID ){} };сразу хочу предупредить, что RelSynchPtr реально будет дееспособным только в том случае, если CRITICAL_SECTION в tagBaseSynchPtr будет задан указателем, иначе при смене базы периодически будут возникать проблемы на выходе из критической секции
есть возможность на этой же основе реализовать и дроссель, но это немного позже...
у меня он уже реализован, но реальных испытаний пока для него небыло.
вспомогательные функции:
template< typename Data, typename Root > inline Data Root::*__cdecl long_to_field( LONG offset ){ union{ LONG offset; Data Root::*field; }retval = { offset }; return retval.field; } template< typename Data, typename Root > inline LONG field_to_long( Data Root::*field ){ union{ Data Root::*field; LONG offset; }retval = { field }; return retval.offset; } template< typename Data, typename Root > inline Root Data::*reverse_field( Data Root::*field ){ return long_to_field< Root, Data >( - field_to_long( field ) ); }
Комментариев нет:
Отправить комментарий