/*!
@brief スレッドをロックするための機能
*/
#ifndef DKUTIL_SYNCHRONIZED_HPP
#define DKUTIL_SYNCHRONIZED_HPP

#include <dkutil/config.hpp>
#include <dkutil_c/dkcThreadLock.h>

namespace dkutil{

#ifdef dkcdMultiThread

/*!
@note

スレッドマネージャーと一緒に使ってください。

<h4>フローチャート</h4>

- CThreadLockを初期化
- スレッドマネージャーを初期化
- スレッドを使う
- スレッドマネージャーの終了処理
- CTheadLockの終了処理

この順で使うこと。

@code
//ダメな使用例
static CProcess gproc //内部でスレッドを使っていて、CThreadLockも使っている。クラス

@endcode
*/
///スレッドをロックしてくれるクラス。Single Threaded Execution pattern ?
class CThreadLock{
	DKC_THREAD_LOCK *mp;
public:
	explicit CThreadLock(){
		mp = NULL;
		mp = dkcAllocThreadLock();
	}
	~CThreadLock(){
		dkcFreeThreadLock(&mp);
	}
	void enter(){
		dkcThreadLock_Lock(mp);	
	}
	bool isLockedByThisThread()const{
		return TRUE== dkcThreadLockIsLockedByThisThread(mp);
	}
	void leave(){
		dkcThreadLock_Unlock(mp);
	}

};

#else

class CThreadLock{
public:
	explicit CThreadLock(){
		
	}
	~CThreadLock(){
		
	}
	void enter(){
		
	}
	bool isLockedByThisThread()const{
		return false;
	}
	void leave(){
		
	}
};


#endif

/*
namespace{
static CThreadLock thread_lock;
}//end of anonymouse namespace
*/
namespace{

template<typename T>
class CThreadLock_Instance : public CThreadLock{
	//static bool mInited
public:
	CThreadLock_Instance() : CThreadLock(){
		//dkcmNOT_ASSERT(CThreadLock::isInited()==false);
	}
	~CThreadLock_Instance(){}
};

}//end of anonymouse namespace

///この実装だと、やばいような気もするが･･･。
///mainより前でエラル時は staticを外してみるとか？
class synchronized{
	//static CThreadLock_Instance<int> mT;
	CThreadLock mT;
public:
	synchronized(){
		mT.enter();
	}
	~synchronized(){
		mT.leave();
	}
	
};

typedef synchronized scoped_criticalsection;

//CThreadLock_Instance<int> synchronized::mT;


#if 0
//マルチスレッドなら
#ifdef _MT //マルチスレッドでビルドする

#	define DKUTIL_LOCKTHREAD(u) \
	{\
		/*Phoenix pattern */ \
		dkutil::synchronized phoenix; \
		if(u.isInited()==false)\
		{/*もし、初期化されていなかったら　もう一回INITする。（復活させる。 */ \
		/*そしてスコープアウトしたらまたKILLする。*/ \
			phoenix.phoenix(u.GetCriticalSection());\
		}\
		try{ u.LockThread()
#	define DKUTIL_UNLOCKTHREAD(u) \
		}catch(...){\
			u.UnlockThread();\
			throw;\
		}\
		u.UnlockThread();\
	}
#	define DKUTIL_MULTITHREAD_SYNDROME_LOCK(u)
#	define DKUTIL_MULTITHREAD_SYNDROME_UNLOCK(u)

#	ifdef USE_DKINGYO_MULTITHREAD_CHECKER //マルチスレッドチェッカーを使う

//かなり安全なマルチスレッド処理を行うためにロックしなくてもいいかな？
//って場所にもロックする。例えば、とあるオブジェクト(クラス)をグローバルにして
//スレッド間でそれにアクセスできる場合などは以下のマクロを使えるようにしなければならない。
//なのでdkutilConfig.hでUSE_DKINGYO_MULTITHREAD_CHECKERを有効にする必要がある。

#		undef	DKUTIL_MULTITHREAD_SYNDROME_LOCK
#		undef	DKUTIL_MULTITHREAD_SYNDROME_UNLOCK
#		define DKUTIL_MULTITHREAD_SYNDROME_LOCK(u)  DKUTIL_LOCKTHREAD(u)
#		define DKUTIL_MULTITHREAD_SYNDROME_UNLOCK(u) DKUTIL_UNLOCKTHREAD(u)
#	endif

#else // シングルスレッドなら

#	define DKUTIL_LOCKTHREAD(u) ((void)0)
#	define DKUTIL_UNLOCKTHREAD(u) ((void)0)
#	define DKUTIL_MULTITHREAD_SYNDROME_LOCK(u) ((void)0)
#	define DKUTIL_MULTITHREAD_SYNDROME_UNLOCK(u) ((void)0)

#endif

#endif


}//end of dkutil namespace



#endif