|
#ifndef _INTERPROCESS_H_
#define _INTERPROCESS_H_
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/interprocess/sync/named_mutex.hpp>
#include <boost/interprocess/sync/scoped_lock.hpp>
#include <sstream>
#include "singleton.hpp"
/// Class incapsulates shared memory segment
class SharedMemorySegment
{
// Segment name
std::string m_strSegmentName;
// Boost segment object to access shared memory
std::auto_ptr< boost::interprocess::shared_memory_object > m_ptrSegment;
// Boost mapped region to map shared memory to address space
std::auto_ptr< boost::interprocess::mapped_region > m_ptrRegion;
// This method resizes shared memory segment to specified size. If bExactSize is true, than greater size segment will be shrinked.
void ResizeSegment( int nSize, bool bExactSize );
public:
/// Class constructor
/// @param strSegmentName Shared memory segment name
SharedMemorySegment( const std::string& strSegmentName );
/// Method resizes and returns pointer to memory segment
/// @param nSize Needed neegment size
/// @param bExactSize Set it to TRUE if you need segment of exactly nSize bytes
void* GetMemory( int nSize, bool bExactSize = false );
/// Method returns current segment size
int GetSize();
/// Method returns segment name
std::string GetSegmentName();
/// Method removes segment
void Remove();
};
/// Serializer class which is used to store data in shared memory
template < class T >
class ObjectSerializer
{
// Revision id of current object
int m_nRevId;
// Current object instance
T m_obj;
// Stream stores serialized object data
std::stringstream m_stream;
// Flag indicates when reserialization in stream needed
bool m_bNeedUpdateStream;
// Method updates stream
void UpdateStream()
{
if( !m_bNeedUpdateStream )
return;
m_stream.str( "" );
boost::archive::binary_oarchive ar( m_stream );
int nNewRevId = m_nRevId + 1;
ar << nNewRevId;
ar << m_obj;
m_bNeedUpdateStream = false;
}
public:
/// Constructor
ObjectSerializer()
: m_nRevId( -1 ),
m_stream( std::ios_base::out | std::ios_base::in | std::ios_base::binary ),
m_bNeedUpdateStream( true )
{
}
/// This method serializes current object to given data block
/// @param lpData Pointer to data block
/// @param nSize Point to integer which retrieves stored data size
void Serialize( void* lpData, int& nSize )
{
UpdateStream();
memcpy( lpData, m_stream.str().c_str(), m_stream.str().size() );
nSize = m_stream.str().size();
}
/// This method deserializes object from given data block
/// @param lpData Pointer to data block
/// @param nSize Size of data block
void DeSerialize( const void* lpData, int nSize )
{
m_stream.str( std::string( ( const char* )lpData, nSize ) );
try
{
boost::archive::binary_iarchive ar( m_stream );
int nRevId;
ar >> nRevId;
// If shared object revision is greater than current object revision - load it
if( nRevId > m_nRevId )
{
ar >> m_obj;
m_nRevId = nRevId;
m_bNeedUpdateStream = false;
}
}
catch( boost::archive::archive_exception& e )
{
m_obj = T();
m_bNeedUpdateStream = true;
}
}
/// This methos updates last revision id from shared memory
/// @param lpData Pointer to shared data block
/// @param nSize Size of shared data block
void UpdateRevisionId( const void* lpData, int nSize )
{
m_stream.str( std::string( ( const char* )lpData, nSize ) );
try
{
boost::archive::binary_iarchive ar( m_stream );
ar >> m_nRevId;
}
catch( boost::archive::archive_exception& e )
{
}
m_bNeedUpdateStream = true;
}
/// This methos returns size that is required to store current object
int GetObjectSize()
{
UpdateStream();
return m_stream.str().size();
}
T* GetObject()
{
m_bNeedUpdateStream = true;
return &m_obj;
}
};
/// Singleton class which can store data in shared memory segment
template < class T, class SerializeStrategy = ObjectSerializer< T > >
class InterprocessSingleton
{
// Shared memory object
SharedMemorySegment m_shms;
// Object serialization strategy
SerializeStrategy m_serializer;
// Name of interprocess mutex
std::string m_strMutexName;
// Used muted type
typedef boost::interprocess::named_mutex MutexType;
// Pointer to mutex which synchronize access to shared memory
std::auto_ptr< MutexType > m_ptrMtx;
typedef InterprocessSingleton< T, SerializeStrategy > Self;
// Singleton class is a friend to construct InterprocessSingleton object which constructor is private
friend class Singleton< Self >;
/// Class constructor
InterprocessSingleton()
: m_shms( std::string( "InterprocessSingletonMemory" ) + typeid( T ).name() ),
m_strMutexName( std::string( "InterprocessSingletonMemory" ) + typeid( T ).name() + "_mtx" )
{
}
/// Hide copy constructor and assignment operator to prevent copying
InterprocessSingleton( const InterprocessSingleton& );
InterprocessSingleton& operator=( const InterprocessSingleton& );
public:
/// This method returns reference to instance of interprocess object
static T& Instance()
{
Self& obj = Singleton< Self >::Instance();
if( !obj.m_ptrMtx.get() )
obj.m_ptrMtx = std::auto_ptr< MutexType >( new MutexType( boost::interprocess::open_or_create, obj.m_strMutexName.c_str() ) );
boost::interprocess::scoped_lock< MutexType > lock( *obj.m_ptrMtx );
int nSize = obj.m_serializer.GetObjectSize();
obj.m_serializer.DeSerialize( obj.m_shms.GetMemory( nSize ), obj.m_shms.GetSize() );
return *obj.m_serializer.GetObject();
}
/// Method saves current object in shared memory
static void Commit()
{
Self& obj = Singleton< Self >::Instance();
if( !obj.m_ptrMtx.get() )
obj.m_ptrMtx = std::auto_ptr< MutexType >( new MutexType( boost::interprocess::open_or_create, obj.m_strMutexName.c_str() ) );
boost::interprocess::scoped_lock< MutexType > lock( *obj.m_ptrMtx );
int nSize = obj.m_serializer.GetObjectSize();
obj.m_serializer.UpdateRevisionId( obj.m_shms.GetMemory( nSize ), obj.m_shms.GetSize() );
obj.m_serializer.Serialize( obj.m_shms.GetMemory( nSize, true ), nSize );
}
/// Method clears all data: deletes shared memory segment, deletes interprocess mutex
static void Clear()
{
Self& obj = Singleton< Self >::Instance();
obj.m_shms.Remove();
MutexType::remove( obj.m_strMutexName.c_str() );
}
};
#endif
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.