просто, захотелось его продолжить, интересно же :)) ...
заведем базовый класс:
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 )
);
}
Комментариев нет:
Отправить комментарий