radboudp
January 7th, 2005, 06:25 AM
Hi again,
In my now maybe well known service (see thread: Threads - how much time do they really use???) I have encountered a second problem in which I hope you guys can aid me. In return I am going to post to of my own base classes here that might be found usefull. :)
For critical sections (cs) I use a self build class that uses the low level OS calls for cs's:
--- Code ---
class CMyCritSection
{
public:
CMyCritSection();
virtual ~CMyCritSection();
// Attributes
public:
private:
CRITICAL_SECTION m_critSec;
int m_nLockCount;
// Methods
public:
void Lock(); // Locks the critical section
void Unlock(); // Releases the critical section
bool TryLock(); // Tries to lock the section. If it is not already locked, it takes ownership of the thread. If it is already locked it returns false without locking.
int GetLockCount() // Returns the number of times this object is locked...
{ return m_nLockCount; }
private:
};
//---------------------------------------------------------------------------
// Construction/Destruction
CMyCritSection::CMyCritSection()
: m_nLockCount( 0 )
{
::InitializeCriticalSection( &m_critSec );
}
CMyCritSection::~CMyCritSection()
{
try
{
::DeleteCriticalSection( &m_critSec );
}
catch ( CException *ex )
{
TCHAR szErrorStr[1024];
UINT uiHelpId = 0;
ex->GetErrorMessage( szErrorStr, 1024, &uiHelpId );
DWORD dwLastError = ::GetLastError();
_ASSERT( FALSE );
}
catch ( ... )
{
DWORD dwLastError = ::GetLastError();
_ASSERT( FALSE );
}
}
//---------------------------------------------------------------------------
void CMyCritSection::Lock()
{
::EnterCriticalSection( &m_critSec );
++ m_nLockCount;
}
void CMyCritSection::Unlock()
{
-- m_nLockCount;
::LeaveCriticalSection( &m_critSec );
}
bool CMyCritSection::TryLock()
{
bool bLocked = (( ::TryEnterCriticalSection( &m_critSec ) == 0 ) ? false : true );
if ( bLocked )
++ m_nLockCount;
return bLocked;
}
//---------------------------------------------------------------------------
--- End code ---
This class I use to protect many resources that are used in multiple threads. I have also used it to create a template class to protect basic attributes with it:
--- Code ---
//---------------------------------------------------------------------------
template< class TYPE >
class CSaveAttrib
{
// Constructor:
public:
CSaveAttrib()
{}
CSaveAttrib( TYPE val )
{ Set( val ); }
CSaveAttrib( CSaveAttrib<TYPE> &val )
{ Set( (TYPE) val ); }
// Attributes:
private:
TYPE m_value;
CMyCritSection m_lock;
// Methods:
public:
TYPE Get()
{ m_lock.Lock(); TYPE ret = m_value; m_lock.Unlock(); return ret; }
void Set( TYPE val )
{ m_lock.Lock(); m_value = val; m_lock.Unlock(); }
// Operators:
public:
// Locking...
void Lock() { m_lock.Lock(); }
void Unlock() { m_lock.Unlock(); }
bool TryLock() { return m_lock.TryLock(); }
// Returns a copy of the attribute
operator TYPE()
{ return Get(); }
// Assignment operator
TYPE operator= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value = val); m_lock.Unlock(); return ret; }
// Arithmic assignment operators
TYPE operator+= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value += val); m_lock.Unlock(); return ret; }
TYPE operator-= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value -= val); m_lock.Unlock(); return ret; }
TYPE operator*= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value *= val); m_lock.Unlock(); return ret; }
TYPE operator/= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value /= val); m_lock.Unlock(); return ret; }
TYPE operator%= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value %= val); m_lock.Unlock(); return ret; }
TYPE operator^= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value ^= val); m_lock.Unlock(); return ret; }
TYPE operator&= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value &= val); m_lock.Unlock(); return ret; }
TYPE operator|= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value |= val); m_lock.Unlock(); return ret; }
// Increment/decrement operators
TYPE operator++ ()
{ m_lock.Lock(); TYPE ret = (++ m_value); m_lock.Unlock(); return ret; }
TYPE operator-- ()
{ m_lock.Lock(); TYPE ret = (-- m_value); m_lock.Unlock(); return ret; }
TYPE operator++ ( int )
{ m_lock.Lock(); TYPE ret = (m_value ++); m_lock.Unlock(); return ret; }
TYPE operator-- ( int )
{ m_lock.Lock(); TYPE ret = (m_value --); m_lock.Unlock(); return ret; }
// Bitshift assignment operators
TYPE operator<<= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value <<= val); m_lock.Unlock(); return ret; }
TYPE operator>>= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value >>= val); m_lock.Unlock(); return ret; }
// Unary Arithmetic Operators
TYPE operator+ ()
{ m_lock.Lock(); TYPE ret = (+m_value); m_lock.Unlock(); return ret; }
TYPE operator- ()
{ m_lock.Lock(); TYPE ret = (-m_value); m_lock.Unlock(); return ret; }
TYPE operator! ()
{ m_lock.Lock(); TYPE ret = (!m_value); m_lock.Unlock(); return ret; }
TYPE operator~ ()
{ m_lock.Lock(); TYPE ret = (~m_value); m_lock.Unlock(); return ret; }
};
//---------------------------------------------------------------------------
--- End code ---
As I said I protect many things with it. My service has a global theService, much like the global theApp you get with a standard MFC application project. In the class of this service I have used CSaveAttrib<> many times (32 at present time). Some are statistics, others are flags etc... CMyCritSection is also used to protect list (MFC CPtrList), IO objects, etc...
Example:
CSaveAttrib<bool> m_bIsClosing;
CSaveAttrib<UINT> m_uiSentItems;
CSaveAttrib<bool> m_bIsActive;
Question one:
Do you guys feel that it is a problem to have many instances of my CMyCritSection??
Question two:
On destruction of the theService instance when the service is stopped I get an exception on two of these CSaveAttrib<> instances. The exception occurs in the ::DeleteCriticalSection() call in the destructor of CMyCritSection. Any clue why this may be?
Many thanks in advance!
-Radboud
In my now maybe well known service (see thread: Threads - how much time do they really use???) I have encountered a second problem in which I hope you guys can aid me. In return I am going to post to of my own base classes here that might be found usefull. :)
For critical sections (cs) I use a self build class that uses the low level OS calls for cs's:
--- Code ---
class CMyCritSection
{
public:
CMyCritSection();
virtual ~CMyCritSection();
// Attributes
public:
private:
CRITICAL_SECTION m_critSec;
int m_nLockCount;
// Methods
public:
void Lock(); // Locks the critical section
void Unlock(); // Releases the critical section
bool TryLock(); // Tries to lock the section. If it is not already locked, it takes ownership of the thread. If it is already locked it returns false without locking.
int GetLockCount() // Returns the number of times this object is locked...
{ return m_nLockCount; }
private:
};
//---------------------------------------------------------------------------
// Construction/Destruction
CMyCritSection::CMyCritSection()
: m_nLockCount( 0 )
{
::InitializeCriticalSection( &m_critSec );
}
CMyCritSection::~CMyCritSection()
{
try
{
::DeleteCriticalSection( &m_critSec );
}
catch ( CException *ex )
{
TCHAR szErrorStr[1024];
UINT uiHelpId = 0;
ex->GetErrorMessage( szErrorStr, 1024, &uiHelpId );
DWORD dwLastError = ::GetLastError();
_ASSERT( FALSE );
}
catch ( ... )
{
DWORD dwLastError = ::GetLastError();
_ASSERT( FALSE );
}
}
//---------------------------------------------------------------------------
void CMyCritSection::Lock()
{
::EnterCriticalSection( &m_critSec );
++ m_nLockCount;
}
void CMyCritSection::Unlock()
{
-- m_nLockCount;
::LeaveCriticalSection( &m_critSec );
}
bool CMyCritSection::TryLock()
{
bool bLocked = (( ::TryEnterCriticalSection( &m_critSec ) == 0 ) ? false : true );
if ( bLocked )
++ m_nLockCount;
return bLocked;
}
//---------------------------------------------------------------------------
--- End code ---
This class I use to protect many resources that are used in multiple threads. I have also used it to create a template class to protect basic attributes with it:
--- Code ---
//---------------------------------------------------------------------------
template< class TYPE >
class CSaveAttrib
{
// Constructor:
public:
CSaveAttrib()
{}
CSaveAttrib( TYPE val )
{ Set( val ); }
CSaveAttrib( CSaveAttrib<TYPE> &val )
{ Set( (TYPE) val ); }
// Attributes:
private:
TYPE m_value;
CMyCritSection m_lock;
// Methods:
public:
TYPE Get()
{ m_lock.Lock(); TYPE ret = m_value; m_lock.Unlock(); return ret; }
void Set( TYPE val )
{ m_lock.Lock(); m_value = val; m_lock.Unlock(); }
// Operators:
public:
// Locking...
void Lock() { m_lock.Lock(); }
void Unlock() { m_lock.Unlock(); }
bool TryLock() { return m_lock.TryLock(); }
// Returns a copy of the attribute
operator TYPE()
{ return Get(); }
// Assignment operator
TYPE operator= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value = val); m_lock.Unlock(); return ret; }
// Arithmic assignment operators
TYPE operator+= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value += val); m_lock.Unlock(); return ret; }
TYPE operator-= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value -= val); m_lock.Unlock(); return ret; }
TYPE operator*= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value *= val); m_lock.Unlock(); return ret; }
TYPE operator/= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value /= val); m_lock.Unlock(); return ret; }
TYPE operator%= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value %= val); m_lock.Unlock(); return ret; }
TYPE operator^= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value ^= val); m_lock.Unlock(); return ret; }
TYPE operator&= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value &= val); m_lock.Unlock(); return ret; }
TYPE operator|= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value |= val); m_lock.Unlock(); return ret; }
// Increment/decrement operators
TYPE operator++ ()
{ m_lock.Lock(); TYPE ret = (++ m_value); m_lock.Unlock(); return ret; }
TYPE operator-- ()
{ m_lock.Lock(); TYPE ret = (-- m_value); m_lock.Unlock(); return ret; }
TYPE operator++ ( int )
{ m_lock.Lock(); TYPE ret = (m_value ++); m_lock.Unlock(); return ret; }
TYPE operator-- ( int )
{ m_lock.Lock(); TYPE ret = (m_value --); m_lock.Unlock(); return ret; }
// Bitshift assignment operators
TYPE operator<<= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value <<= val); m_lock.Unlock(); return ret; }
TYPE operator>>= ( TYPE val )
{ m_lock.Lock(); TYPE ret = (m_value >>= val); m_lock.Unlock(); return ret; }
// Unary Arithmetic Operators
TYPE operator+ ()
{ m_lock.Lock(); TYPE ret = (+m_value); m_lock.Unlock(); return ret; }
TYPE operator- ()
{ m_lock.Lock(); TYPE ret = (-m_value); m_lock.Unlock(); return ret; }
TYPE operator! ()
{ m_lock.Lock(); TYPE ret = (!m_value); m_lock.Unlock(); return ret; }
TYPE operator~ ()
{ m_lock.Lock(); TYPE ret = (~m_value); m_lock.Unlock(); return ret; }
};
//---------------------------------------------------------------------------
--- End code ---
As I said I protect many things with it. My service has a global theService, much like the global theApp you get with a standard MFC application project. In the class of this service I have used CSaveAttrib<> many times (32 at present time). Some are statistics, others are flags etc... CMyCritSection is also used to protect list (MFC CPtrList), IO objects, etc...
Example:
CSaveAttrib<bool> m_bIsClosing;
CSaveAttrib<UINT> m_uiSentItems;
CSaveAttrib<bool> m_bIsActive;
Question one:
Do you guys feel that it is a problem to have many instances of my CMyCritSection??
Question two:
On destruction of the theService instance when the service is stopped I get an exception on two of these CSaveAttrib<> instances. The exception occurs in the ::DeleteCriticalSection() call in the destructor of CMyCritSection. Any clue why this may be?
Many thanks in advance!
-Radboud