Click here to Skip to main content
15,885,906 members
Articles / Mobile Apps / Windows Mobile

Code that debugs itself

Rate me:
Please Sign up or sign in to vote.
4.78/5 (74 votes)
17 Feb 200534 min read 311.5K   5K   184  
A set of macros for detecting and reporting critical errors, combined with a technique of writing solid code.
/////////////////////////////////////////////////////////////////////////////////
//
//  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

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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Team Leader OpTier
Israel Israel
Programming computers since entering the university in 1992, but dreaming of programming long time before putting hands on my first computer.

Experienced in cross-platform software development using C++ and Java, as well as rapid GUI development using Delphi/C#. Strong background in networking, relational databases, Web development, and mobile platforms.

Like playing guitar, visiting historical sites (not in the Internet, in the car Smile | :) ) and cooking meat with friends (sorry about vegetarians). Look for more information on www.schetinin.com

Comments and Discussions