
/*!
@since 2003/9/29
*/


#ifndef _dkutilCriticalSection__h_
#define _dkutilCriticalSection__h_

#include "dKingyoMacro.h"
#include "dkutilDefinedC.h"

namespace dkutil{

#ifdef _MT //Multi Threadだったら。

#	ifdef USE_DKINGYO_YANESDK3RD	//yaneSDK3rdを使うのなら

class DKCriticalSection : public CCriticalSection{
public:
	DKCriticalSection() : CCriticalSection(){}
	virtual ~DKCriticalSection(){}
};

#	else ///yaneSDK3rdを使わないなら･･･

///yaneSDK3rdを参考にしました。...しかし、コピペに近いかも･･･ごめんなさいm(j◇j)m
class DKCriticalSection{
public:
	DKCriticalSection(){
		::InitializeCriticalSection(&m_csCriticalSection);
		m_dwLockedThread = (DWORD)-1;
		mLockCount	= 0;
		//ODS("Init CriticalSection");
	}

	virtual ~DKCriticalSection(){
		::DeleteCriticalSection(&m_csCriticalSection);
		if (mLockCount!=0) {
#	ifdef USE_DKINGYO_THROW
			throw std::logic_error("DKCriticalSectionをEnterした回数だけLeaveしないまま終了している");
#	else
			MB("DKCriticalSectionをEnterした回数だけLeaveしないまま終了している");
#	endif
		}
		//ODS("End CriticalSection");
	}

	///	CriticalSectionに入る
	void Enter(){
		::EnterCriticalSection(&m_csCriticalSection);
		
		m_dwLockedThread = ::GetCurrentThreadId();
		//	↑異なるスレッドからここに入ってくることはできない
		//	(CriticalSectionの定義より)
		mLockCount++;

	}

	///CriticalSectionから抜ける
	void Leave(){

		if (mLockCount==0){
#	ifdef USE_DKINGYO_THROW
			throw  std::logic_error("DKCriticalSectionをEnterしていないのにLeaveしている");
#	else
			MB("DKCriticalSectionをEnterしていないのにLeaveしている");
#	endif
		}

		if (--mLockCount==0) {
			m_dwLockedThread = (DWORD)-1;
		}
		//	↑Leaveした直後に他スレッドがEnterする可能性がある
		::LeaveCriticalSection(&m_csCriticalSection);
	}

	bool IsLockedByThisThread() const{
		DWORD dw = ::GetCurrentThreadId();
		return (m_dwLockedThread == dw);
	}
	
protected:
	CRITICAL_SECTION m_csCriticalSection;
	DWORD				m_dwLockedThread;	//	LockしているThreadId(0:非Lock)
	int					mLockCount;		//	Lockされている回数
			//	(同一スレッドならば複数回Lockできるので)
};

#	endif //end of USE_DKINGYO_YANESDK3RD	

#else //Single Threadだったら･･･

class DKCriticalSection{
public:
	DKCriticalSection(){

	}

	virtual ~DKCriticalSection(){

	}
	///	CriticalSectionに入る
	void Enter(){
	}
	///CriticalSectionから抜ける
	void Leave(){

	}

	bool IsLockedByThisThread() const{
		return false;
	}
protected:
};

#endif//end of _MT


namespace private_{

extern DKCriticalSection &GetCriticalSection();

}

}//end of dkutil namespace
















#endif //end of include once 