/////////////////////////////////////////////////////////////////////////////////
//
// Set of simple synchronization classes
//
// Copyright (c) 2003-2004
// Andrew Schetinin
//
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
//
// Permission to use or copy this software for any purpose is hereby granted
// without fee, provided the above notices are retained on all copies.
// Permission to modify the code and to distribute modified code is granted,
// provided the above notices are retained, and a notice that the code was
// modified is included with the above copyright notice.
//
// This software accompanies the article "Code that debugs itself"
// located at http://www.codeproject.com/debug/qafdebug.asp
//
// You are welcomed to report bugs, send comments and post code modifications
// to aschetinin@hotmail.com
//
/////////////////////////////////////////////////////////////////////////////////
///
/// @file CSyncCS.h "../Include/CSyncCS.h"
/// @brief Simple synchronization classes.
///
/// This file defines simple synchronization classes like critical
/// sections and mutexes.
#ifndef _QAFCSYNC_H_
#define _QAFCSYNC_H_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <cassert>
#ifdef WIN32
#include <wtypes.h>
#endif
#include "qafdebug.h"
//
// Using of BEGIN_SYNC and END_SYNC:
//
// // Define it somewhere in your header file
// CAutoCS m_cs; // critical section object
//
// // And synchronize your code in CPP file
// BEGIN_SYNC( m_cs );
// .... do whatever you need ...
// END_SYNC;
//
/// Special define for organizing exception-safe synchronized blocks of code.
/// This is the start macro, it must be enclosed with END_SYNC
#define BEGIN_SYNC( sync_obj ) do { CAutoLockCS sync( sync_obj )
/// Special define for organizing exception-safe synchronized blocks of code.
/// This is the end macro
#define END_SYNC } while( FALSE )
#ifdef WIN32
///
typedef LPCTSTR Q_LPCTSTR;
#else
/// typedef for Linux systems
typedef unsigned int CRITICAL_SECTION;
/// typedef for Linux systems
typedef void * HANDLE;
/// Timeout value
const unsigned int INFINITE = 0xFFFFFFFF;
///
typedef const char * Q_LPCTSTR;
#endif
/// A simple synchronization class, designed to be used as an automatic variable.
/// Once its instance is instanciated, it locks its visibility scope.
class CSyncCS
{
public:
/// Flag that the critical section object must be constructed or destroyed
enum CSOP { CS_NOP = 0, CS_CREATE = 1, CS_DESTROY = 2 };
/// Constructor creates and enters the critical section
CSyncCS( CRITICAL_SECTION * pcs, const CSOP csop = CS_NOP )
{
m_pcs = pcs;
m_csop = csop;
#ifdef WIN32
if( CS_CREATE == m_csop )
InitializeCriticalSection( m_pcs );
EnterCriticalSection( m_pcs );
#endif
}
/// Destructor leaves and destroys the critical section
~CSyncCS()
{
#ifdef WIN32
LeaveCriticalSection( m_pcs );
if( CS_DESTROY == m_csop )
DeleteCriticalSection( m_pcs );
#endif
}
private:
/// Critical section is used for synchronization
CRITICAL_SECTION * m_pcs;
/// Flag that the critical section object must be constructed or destroyed
CSOP m_csop;
};
/// Improved version of CSyncCS class
class CAutoCS
{
public:
/// Constructor creates the critical section
CAutoCS()
{
#ifdef WIN32
InitializeCriticalSection( &m_cs );
#endif
}
/// Destructor destroys the critical section
~CAutoCS()
{
#ifdef WIN32
DeleteCriticalSection( &m_cs );
#endif
}
/// Enter the critical section
bool Lock()
{
#ifdef WIN32
EnterCriticalSection( &m_cs );
#endif
return true;
}
/// Leave the critical section
void Unlock()
{
#ifdef WIN32
LeaveCriticalSection( &m_cs );
#endif
}
private:
/// Critical section is used for synchronization
CRITICAL_SECTION m_cs;
};
/// Automatic locker for different synchronization objects.
template <class SyncClass>
class CLockCS
{
public:
/// Constructor locks the synchronization object
CLockCS( SyncClass &SyncObj ) : m_SyncObj(SyncObj), m_bLocked(false)
{
m_bLocked = m_SyncObj.Lock();
}
/// Constructor locks the synchronization object
CLockCS( SyncClass &SyncObj, unsigned int uiTimeout )
: m_SyncObj(SyncObj), m_bLocked(false)
{
m_bLocked = m_SyncObj.Lock( uiTimeout );
}
/// Destructor unlocks the synchronization object
~CLockCS()
{
if( m_bLocked )
{
m_SyncObj.Unlock();
m_bLocked = false;
}
}
/// Return true if the lock succeeded
bool isLocked() const
{
return m_bLocked;
}
private:
/// Reference to the synchronization object
SyncClass & m_SyncObj;
/// Flag that it is locked
bool m_bLocked;
};
/// Shortcut for autolocking critical section.
typedef CLockCS<CAutoCS> CAutoLockCS;
/// Simple mutex class that is compatible to the CLockCS class.
class CMutex
{
public:
/// default constructor
CMutex() : m_hMutex(NULL), m_bOwned(false)
{
#ifdef WIN32
m_hMutex = CreateMutex( NULL, FALSE, NULL );
if( Q_ASSERT( NULL != m_hMutex ) )
m_bOwned = true;
#endif
}
/// default constructor
CMutex( Q_LPCTSTR szMutexName ) : m_hMutex(NULL), m_bOwned(false)
{
#ifdef WIN32
m_hMutex = CreateMutex( NULL, FALSE, szMutexName );
if( Q_ASSERT( NULL != m_hMutex ) )
m_bOwned = true;
#endif
}
/// copy constructor
CMutex( HANDLE hMutex ) : m_hMutex(hMutex), m_bOwned(false)
{
Q_ASSERT( NULL != m_hMutex );
}
/// copy constructor
CMutex( const CMutex & obj ) : m_hMutex(obj.m_hMutex), m_bOwned(false)
{
Q_ASSERT( NULL != m_hMutex );
}
/// destructor
~CMutex()
{
if( m_bOwned )
{
#ifdef WIN32
Q_ASSERT( CloseHandle( m_hMutex ) );
#endif
m_hMutex = NULL;
}
}
/// get the handle of the mutex. this handle must not be closed
HANDLE GetHandle() const
{
return m_hMutex;
}
/// Enter the critical section
bool Lock( unsigned long dwMilliseconds = INFINITE )
{
#ifdef WIN32
DWORD dwRet = WaitForSingleObject( m_hMutex, dwMilliseconds );
return Q_ASSERT( WAIT_OBJECT_0 == dwRet );
#else
return true;
#endif
}
/// Leave the critical section
void Unlock()
{
#ifdef WIN32
Q_ASSERT( ReleaseMutex( m_hMutex ) );
#endif
}
protected:
private:
/// Mutex handle
HANDLE m_hMutex;
/// Flag if this handle is owned by the object
bool m_bOwned;
/// assignment operator
CMutex & operator=( const CMutex & obj )
{
Q_ASSERT( false );
assert( false );
if( this != &obj )
{
// copy the members
}
return *this;
}
};
/// Simple semaphore class that is compatible to the CLockCS class.
class CSemaphore
{
public:
/// regular constructor
CSemaphore( const int nMaxCount ) : m_hSemaphore(NULL), m_bOwned(false)
{
#ifdef WIN32
m_hSemaphore = CreateSemaphore( NULL, nMaxCount, nMaxCount, NULL );
if( Q_ASSERT( NULL != m_hSemaphore ) )
m_bOwned = true;
#endif
}
/// default constructor
CSemaphore( Q_LPCTSTR szSemaphoreName, const int nMaxCount ) :
m_hSemaphore(NULL), m_bOwned(false)
{
#ifdef WIN32
m_hSemaphore = CreateSemaphore( NULL, nMaxCount, nMaxCount,
szSemaphoreName );
if( Q_ASSERT( NULL != m_hSemaphore ) )
m_bOwned = true;
#endif
}
/// copy constructor
CSemaphore( HANDLE hSemaphore, bool bMakeOwn ) :
m_hSemaphore(NULL), m_bOwned(false)
{
#ifdef WIN32
if( bMakeOwn )
{
HANDLE hProcess = GetCurrentProcess();
m_bOwned = TRUE == DuplicateHandle( hProcess, hSemaphore,
hProcess, &m_hSemaphore, 0, FALSE, DUPLICATE_SAME_ACCESS );
}
Q_ASSERT( NULL != m_hSemaphore );
#endif
}
/// copy constructor
CSemaphore( const CSemaphore & obj ) : m_hSemaphore(NULL),
m_bOwned(false)
{
#ifdef WIN32
HANDLE hProcess = GetCurrentProcess();
m_bOwned = TRUE == DuplicateHandle( hProcess, obj.GetHandle(),
hProcess, &m_hSemaphore, 0, FALSE, DUPLICATE_SAME_ACCESS );
Q_ASSERT( NULL != m_hSemaphore );
#endif
}
/// assignment operator
CSemaphore & operator=( const CSemaphore & obj )
{
#ifdef WIN32
if( this != &obj )
{
clear();
HANDLE hProcess = GetCurrentProcess();
m_bOwned = TRUE == DuplicateHandle( hProcess, obj.GetHandle(),
hProcess, &m_hSemaphore, 0, FALSE, DUPLICATE_SAME_ACCESS );
Q_ASSERT( NULL != m_hSemaphore );
}
#endif
return *this;
}
/// destructor
~CSemaphore()
{
clear();
}
/// get the handle of the mutex. this handle must not be closed
HANDLE GetHandle() const
{
return m_hSemaphore;
}
/// Enter the critical section
bool Lock( unsigned long dwMilliseconds = INFINITE )
{
#ifdef WIN32
DWORD dwRet = WaitForSingleObject( m_hSemaphore, dwMilliseconds );
return Q_CHECK( WAIT_OBJECT_0, dwRet );
#else
return true;
#endif
}
/// Leave the critical section
void Unlock()
{
#ifdef WIN32
Q_ASSERT( ReleaseSemaphore( m_hSemaphore, 1, NULL ) );
#endif
}
protected:
private:
/// Semaphore handle
HANDLE m_hSemaphore;
/// Flag if this handle is owned by the object
bool m_bOwned;
/// Clear and free handles
void clear()
{
#ifdef WIN32
if( m_bOwned )
Q_ASSERT( CloseHandle( m_hSemaphore ) );
#endif
m_hSemaphore = NULL;
m_bOwned = false;
}
/// default constructor - disabled
CSemaphore() : m_hSemaphore(NULL), m_bOwned(false) {}
};
/// Shortcut for autolocking critical section.
typedef CLockCS<CSemaphore> CSemaphoreLock;
///////////////////////////////////////////////
// END OF FILE
///////////////////////////////////////////////
#endif