#ifndef _xbTHREAD_
#define _xbTHREAD_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbThread
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#ifndef _xbENGINE_
#	include "xbEngine.h"
#endif

#ifndef _xbLOCK_
#	include "xbLock.h"
#endif

#ifndef _xbSYNC_
#	include "xbSync.h"
#endif

#ifndef _xbSTRING_
#	include "xbString.h"
#endif

#ifdef xbOS_MSWIN
#	include "osdep/mswin/xbODthreadLow.h"
#else
#	pragma message("XDCBASE: ERROR: platform not supported")
#endif

#define xbTHREADLOCK_TRYCNT		50
#define xbTHREADLOCK_TRYSLEEP	100

#define xbTHREADCREATE_TRYCNT	5
#define xbTHREADNB_TRYCNT		3
#define xbTHREADNB_TRYSLEEP		100

#define xbTHREADCLOSEALL_TRYCNT		500
#define xbTHREADCLOSEALL_TRYSLEEP	200

#define xbTHREADCLOSE_NREQTRYCNT	50
#define xbTHREADCLOSE_NREQWAITCNT	10
#define xbTHREADCLOSE_TRYCNT		500
#define xbTHREADCLOSE_TRYSLEEP		100

#define xbTHREADDESTROY_TRYCNT		50
#define xbTHREADDESTROY_TRYSLEEP	200

#define xbTHREADGET_TRYCNT		20
#define xbTHREADGET_TRYSLEEP	100

enum xbThreadPriority
{
xbThreadCritical = THREAD_PRIORITY_TIME_CRITICAL,
xbThreadHighest = THREAD_PRIORITY_HIGHEST,
xbThreadHigh = THREAD_PRIORITY_ABOVE_NORMAL,
xbThreadNormal = THREAD_PRIORITY_NORMAL,
xbThreadLow = THREAD_PRIORITY_BELOW_NORMAL,
xbThreadLowest = THREAD_PRIORITY_LOWEST,
xbThreadIdle = THREAD_PRIORITY_IDLE
};

interface sIxbThreadBaseCb;
interface xbEXPORT __declspec(uuid("{4721E866-2F5E-487f-AA2B-3EF54D9D6C18}"))
	sIxbThread:public sIxbThreadContextObject
{
	virtual bool				GetLock(xbLock *pLck,xbOpMode opMode = xbOp_Required) = 0;
	virtual DWORD				Suspend(xbOpMode opMode = xbOp_Required) = 0;
	virtual DWORD				Resume(xbOpMode opMode = xbOp_Required) = 0;
	virtual bool				Close(xbLock *pThreadLckToUnlock,LPCSTR pReason,xbOpMode opMode /*= xbOp_Required*/) = 0;
	virtual void				AskClose(LPCSTR pReason) = 0;
	virtual bool				CloseIfNotBusy(xbLock *pThreadLckToUnlock,LPCSTR pReason) = 0;
	virtual HANDLE				GetHandle() = 0;
	virtual DWORD				GetId() = 0;
	virtual xbString			GetLabel() = 0;
	virtual xbThreadPriority	GetPriority() = 0;
	virtual bool				SetPriority(xbThreadPriority priority,xbOpMode opm =xbOp_Required) = 0;
	virtual void				PostMessage( UINT message , WPARAM wParam, LPARAM lParam ) = 0;
	virtual void				StartCoInit() = 0;
	virtual void				StopCoInit() = 0;
	virtual bool				IsCoInitStarted() const = 0;
	virtual sIxbThreadBaseCb	*getCB() const = 0;

	xbPropertyR(HANDLE,Handle);
	xbPropertyR(xbString,Label);
	xbPropertyR(DWORD,Id);
};

interface  xbEXPORT __declspec(uuid("{DA2EC1CC-762F-4dde-A3F6-50D099416C18}"))
	sIxbThreadCoInit
{
	virtual bool onThreadCoInitStart(xbSectLock *pThreadCenterLck,sIxbThread *pTh,void **ppCtx) = 0;
	virtual bool onThreadCoInitStop(xbSectLock *pThreadCenterLck,sIxbThread *pTh,void *pCtx) = 0;
};

interface xbEXPORT __declspec(uuid("{F8595FAE-C7B8-41d4-AC9F-73C14A77089D}"))
	sIxbThreadBaseCb:public sIxbBase
{
	virtual void	onStart(sIxbThread *pTh) = 0;
	virtual DWORD	onStop(sIxbThread *pTh,DWORD ret) = 0;
	virtual DWORD	onStopForce(sIxbThread *pTh,DWORD ret) = 0;
	virtual bool	closeIfNotBusy(sIxbThread *pTh,xbLock *pThreadLckToUnlock,LPCSTR pReason) = 0;
	virtual void	onCloseAsked(sIxbThread *pTh,LPCSTR pReason) = 0;
	virtual xbThreadEventObject *GetThreadEvent() = 0;
};

interface xbEXPORT __declspec(uuid("{7C37A9B4-C275-4693-9140-C85CE0A41B64}"))
	sIxbThreadMsgCb:public sIxbThreadBaseCb
{
	virtual bool	onThreadMsg(sIxbThread *pTh,MSG *pMsg,bool bQuit) = 0;
};

interface xbEXPORT __declspec(uuid("{B835C1E5-22DD-4442-931C-59AFE7A88890}"))
	sIxbThreadCb:public sIxbThreadBaseCb
{
	virtual DWORD	onThreadProc(sIxbThread *pTh) = 0;

#ifdef _xbOBSOLETE_
protected:
	virtual bool	askClose(sIxbThread *pTh,LPCSTR pReason) {return false;}
#endif
};

class xbEXPORT xbThreadCoInit
{
public:
	xbThreadCoInit()
	{
		m_bInit = false;
		m_pCtx = NULL;
		m_pTh = NULL;
	}
	void Start(sIxbThread *pTh = NULL);
	void Stop();
	bool IsStarted() const
	{
		return m_bInit;
	}
	~xbThreadCoInit()
	{
		eProtect(Stop());
	}
protected:
	bool m_bInit;
	void *m_pCtx;
	sIxbThread *m_pTh;
};

class xbEXPORT xbThreadBaseCb:public xbBase,public sIxbThreadBaseCb
{
public:
	xbThreadBaseCb() {}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbThreadBaseCb);
		return xbBase::GetInterface(riid,ppInterf);
	}
};

class xbEXPORT xbThreadMsgCb:public xbBase,public sIxbThreadMsgCb
{
public:
	xbThreadMsgCb() {}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbThreadMsgCb);
		xbImplInterface(sIxbThreadBaseCb);
		return xbBase::GetInterface(riid,ppInterf);
	}
};

class xbEXPORT xbThreadCb:public xbBase,public sIxbThreadCb
{
public:
	xbThreadCb() {}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbThreadCb);
		xbImplInterface(sIxbThreadBaseCb);
		return xbBase::GetInterface(riid,ppInterf);
	}
};

class xbUseThreadCenter;
class xbEXPORT __declspec(uuid("{8C9BB171-A9EC-44b0-8A81-29FC681DC080}"))
	xbThreadCenter:public xbEngine
{
public:
	xbThreadCenter(const char *pLabel,const xbEngines &engUsed = xbEngines())
		:xbEngine(xbEngineStart_OnUse,pLabel,engUsed)
	{
		m_cThread = m_cThreadPeak = 0;
		m_cThreadClosed = m_cThreadDone = 0;
		m_pCoInitCb = NULL;
		m_cUseLock = 0;
		m_bAppLock = false;
	}
	virtual ~xbThreadCenter()
	{
		xbRdbgAssert(m_cUseLock == 0);
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbThreadCenter);
		return xbEngine::GetInterface(riid,ppInterf);
	}
	void NewThread(const xbString &label,sIxbThreadBaseCb *pCb,bool bTryCloseOthers = true)
	{
		createThread(label,pCb,bTryCloseOthers,false);
	}
	sIxbThread *NewSuspendedThread(const xbString &label,sIxbThreadBaseCb *pCb,bool bTryCloseOthers = true)
	{
		return createThread(label,pCb,bTryCloseOthers,true);
	}
	void ResetPerfStats();
	int GetThreadCount() const;
	int GetThreadPeakCount() const;
	uint GetThreadDoneCount() const;
	uint GetThreadClosedCount() const;
//	void CloseAll();

	void SetCoInit(sIxbThreadCoInit *pCb);
	sIxbThreadCoInit *GetCoInit();
	void StartCoInit(sIxbThread *pTh,void **ppCtx);
	void StopCoInit(sIxbThread *pTh,void *pCtx);

	virtual bool isLockedByMe() const {return m_sect.IsLockedByMe();}
	mutable xbSectShare m_sect;
protected:
	friend xbUseThreadCenter;
	void threadUseLock();
	void threadUseUnlock();

	bool askCloseAll(LPCSTR pReason,bool bUseEnd = false);

	sIxbThread *createThread(const xbString &label,sIxbThreadBaseCb *pCb, bool bTryCloseOthers, bool bSuspended);
	bool tryCloseOthers();
	virtual void onStart();
	virtual bool onStop(bool bForce);

	class Thread:public xbThreadLowBase,public sIxbThread,public sIxbLock
	{
	public:
		Thread(xbThreadCenter *pCenter,const xbString &label,sIxbThreadBaseCb *pCb);
		virtual ~Thread() 
		{
			eProtectTrace(removeFromCenter());
		}

		virtual bool GetInterface(REFIID riid, void ** ppInterf)
		{
			xbImplInterface(sIxbThread);
			xbImplInterface(sIxbThreadContextObject);
			xbImplInterface(sIxbLock);
			return xbThreadLowBase::GetInterface(riid,ppInterf);
		}
		
		//Own methods

		//xbThreadLowBase overrided methods
		virtual int Run();

		// sIxbLock methods
		virtual void				Lock() const;
		virtual void				Unlock() const;

		// sIxbThread methods
		virtual bool				GetLock(xbLock *pLck,xbOpMode opMode = xbOp_Required)
		{
			xbSectLock lck(&m_pThCenter->m_sect);
			if (opMode != xbOp_Required && m_bInClose) 
				return false;
			pLck->Lock(this);
			return true;
		}
		virtual DWORD				Suspend(xbOpMode opMode = xbOp_Required);
		virtual DWORD				Resume(xbOpMode opMode = xbOp_Required);
		virtual bool				Close(xbLock *pThreadLckToUnlock,LPCSTR pReason,xbOpMode opMode /*= xbOp_Required*/);
		virtual void				AskClose(LPCSTR pReason);
		virtual bool				CloseIfNotBusy(xbLock *pThreadLckToUnlock,LPCSTR pReason);
		virtual HANDLE				GetHandle();
		virtual DWORD				GetId();
		virtual xbString			GetLabel();
		virtual xbThreadPriority	GetPriority();
		virtual bool				SetPriority(xbThreadPriority priority,xbOpMode opm);
		virtual void				PostMessage( UINT message , WPARAM wParam, LPARAM lParam );
		virtual void				StartCoInit();
		virtual void				StopCoInit();
		virtual bool				IsCoInitStarted() const;
		virtual sIxbThreadBaseCb	*getCB() const {return m_pCb;}
		
		//sIxbThreadContextObject methods
		virtual void	ThreadContextRelease();
		virtual sIxbThreadContextObject *ThreadContextOld();
		virtual xbThreadEventObject *ThreadEvent();
		virtual bool onThreadShouldStop( ulong evMask ) const;
		virtual bool onThreadMsg(MSG *pMsg,bool *pbQuit);

		//Implementation
		xbHeapNewImpl(Thread);
		void thTrace(const xbString &txt);

		inline bool shouldStop() const
		{
			ulong ev = m_eventPtr.ProcessEvents();
			if (!ev)
				return false;
			return onThreadShouldStop(ev);
		}
	protected:
		void	waitLockEnd(xbSectLock *pLck);
		void	closeMsgQ(xbSectLock *pLck);
		void	removeFromCenter();

		xbThreadCenter		*m_pThCenter;
		int					m_CenterId;

		xbThreadEventPtr	m_eventPtr;

		sIxbThreadBaseCb	*m_pCb;
		xbString			m_label;
		bool				m_bInRun;
		bool				m_bInThreadLock;
		bool				m_bInClose;
		int					m_cCloseTried;
		mutable int			m_cThreadLock;

		xbThreadCoInit		m_coInit;
		sIxbThreadMsgCb		*m_pMsgCb;

		friend xbThreadCenter;
	};

	friend Thread;

	void addThread(Thread *pTh);
	void appLock();
	void appUnlock();

	xbArray<Thread*>	m_arrTh;
	int					m_cThread,m_cThreadPeak;
	uint				m_cThreadClosed,m_cThreadDone;
	long				m_cUseLock;
	bool				m_bAppLock;

	sIxbThreadCoInit	*m_pCoInitCb;
};

extern xbEXPORT xbThreadCenter	g_xbThreadCenter;

template<class targBase> class xbTThreadBase:public targBase
{
protected:
	virtual ~xbTThreadBase()
	{
		xbRdbgAssert(m_pTh == NULL && !m_bCreateAsked);
	}
public:
	xbTThreadBase(xbSectShare *pSect,const xbString &label)
	{
		m_pSect = pSect;
		m_label = label;
		m_bBusy = true;
		m_bCreateAsked = false;
		m_pTh = NULL;
		m_thId = 0;
	}
	void Create(bool bTryCloseOthers = true,xbSectLock *pLck = NULL)
	{
		xbSectLock _lck;
		if (!pLck)
		{
			pLck = &_lck;
			_lck.Lock(m_pSect);
		}
		if (m_pTh || m_bCreateAsked) 
		{
			if (m_eventPtr.ProcessToContinue())
				return;
			pLck->Unlock();
			destroy("Thread creation waiting thread destruction end");
			pLck->Lock(m_pSect);
			if (m_pTh || m_bCreateAsked) 
				xbThrowEsys("xbTThreadBase::Create() failure, can't stop previous thread");

		}
		m_eventPtr.ResumeProcess();
		m_bBusy = true;
		m_bCreateAsked = true;
		try
		{
			pLck->Unlock();
			g_xbThreadCenter.NewThread(m_label,this,bTryCloseOthers);
			pLck->Lock(m_pSect);
		}
		catch(...)
		{
			eProtect(pLck->Lock(m_pSect););
			m_bCreateAsked = false;
			throw;
		}
	}
	sIxbThread *CreateSuspended(bool bTryCloseOthers = true)
	{
		xbSectLock lck(m_pSect);
		if (m_pTh || m_bCreateAsked) 
		{
			if (m_eventPtr.ProcessToContinue())
				return m_pTh;
			lck.Unlock();
			destroy("CreateSuspended");
			lck.Lock(m_pSect);
			if (m_pTh || m_bCreateAsked) 
				xbThrowEsys("xbTThreadBase::Create() failure, can't stop previous thread");

		}
		m_eventPtr.ResumeProcess();
		m_bBusy = true;
		m_bCreateAsked = true;
		try
		{
			lck.Unlock();
			return g_xbThreadCenter.NewSuspendedThread(m_label,this,bTryCloseOthers);
		}
		catch(...)
		{
			eProtect(lck.Lock(m_pSect););
			m_bCreateAsked = false;
			throw;
		}
		return NULL;
	}
	bool	IsBusy() const
	{
//		xbSectLock lck(m_pSect);
		return m_bBusy;
	}
	bool	IsCloseAskedIntOrExt() const
	{//Can be call outside or inside thread
		if (m_thId != ::GetCurrentThreadId())
			return IsCloseAskedExt();
		return IsCloseAskedInt();
	}
	bool	IsCloseAskedExt() const
	{//Call outside thread/external
		xbRdbgAssert(m_thId != ::GetCurrentThreadId());
		return m_eventPtr.ProcessToStop();
	}
protected:
	bool	IsCloseAskedInt() const
	{//Call inside thread/internal
		xbRdbgAssert(m_thId == ::GetCurrentThreadId());
		ulong ev = m_eventPtr.ProcessEvents();
		if (!ev)
			return false;
		return m_pTh->onThreadShouldStop(ev);
	}
	void ResumeTaskProcess()
	{
		xbRdbgAssert(m_thId == ::GetCurrentThreadId());
		m_eventPtr.ResumeTaskProcess();
	}
public:

	bool	setBusy(xbOpMode opm =xbOp_Required)
	{
		xbSectLock lck(m_pSect);
		m_eventPtr.ResumeTaskProcess();
		if (m_eventPtr.ProcessToStop())
		{
			if (opm == xbOp_Required)
				xbThrowEsys("xbTThreadBase("+m_label+")::setBusy() : close asked");
			return false;
		}
		m_bBusy = true;
		return true;
	}
	bool	unsetBusy()
	{
		xbSectLock lck(m_pSect);
		m_bBusy = false;
		return true;
	}
	sIxbThread *GetThread(xbLock *pLckThread,xbOpMode opMode = xbOp_Required)
	{
		xbSectLock lck(m_pSect);
		if (m_eventPtr.ProcessToStop()) 
		{
			if (opMode == xbOp_Required) 
				xbThrowEsys("xbTThreadBase("+m_label+")::GetThread() : close asked");
			return NULL;
		}
		if (!m_bCreateAsked && !m_pTh)
		{
			if (opMode == xbOp_Required) 
				xbThrowEsys("xbTThreadBase("+m_label+")::GetThread() : not created");
			return NULL;
		}
		int cnt = 0;
		for(;;)
		{
			if (++cnt > xbTHREADGET_TRYCNT)
				xbThrowEsys("xbTThreadBase("+m_label+")::GetThread() : timeout (maybe thread suspended)");
			if (m_pTh) 
			{
				if (m_pTh->GetLock(pLckThread,xbOp_Required)) return m_pTh;
				return NULL;
			}
			lck.Unlock();
			xbSleep(xbTHREADGET_TRYSLEEP);
			lck.Lock(m_pSect);
		}
		return NULL;
	}
	bool AskDestroy(LPCSTR pReason,bool *pbInClose = NULL)
	{
		if (pbInClose)
			*pbInClose = false;
		xbSectLock lck(m_pSect);
		if (!m_pTh)
		{
			if (m_bCreateAsked) return false; //wait for creation to destroy thread properly
			return true;
		}
		{
			xbLock lckThread;
			if (!m_pTh->GetLock(&lckThread,xbOp_Optional))
			{
				if (pbInClose)
					*pbInClose = true;
				return false; //thread in close
			}
			m_eventPtr.StopProcess();

			lck.Unlock();
			m_pTh->Close(&lckThread,pReason,xbOp_Optional);
		}
		lck.Lock(m_pSect);
		return m_pTh == NULL;
	}
	xbString getCloseReason() const
	{
		xbSectLock lck(m_pSect);
		return m_closeReason;
	}

protected:
	void destroy(LPCSTR pReason)
	{
		eProtectBegin();
		xbSectLock lck(m_pSect);
		int cnt = 0;
		bool bAskClose = true;
		for(;;)
		{
			if (++cnt > xbTHREADDESTROY_TRYCNT)
				xbThrowEsys("xbTThreadBase("+m_label+")::Destroy() : timeout ("+xbStrFromPtr(m_pTh)+xbString(m_bCreateAsked?"/createAsked":"")+")");
			if (!m_pTh && !m_bCreateAsked) return;

			if (!m_pTh && m_bCreateAsked) 
			{
				lck.Unlock(); 
				bAskClose = true;
			}
			else if (bAskClose || (cnt%10) == 0)
			{
				xbLock lckThread;
				if (m_pTh->GetLock(&lckThread,xbOp_Optional))
				{
					lck.Unlock();
					m_pTh->Close(&lckThread,pReason,xbOp_Optional);
				}
				else lck.Unlock();
				bAskClose = false;
			}
			else lck.Unlock();
			xbSleep(xbTHREADDESTROY_TRYSLEEP);
			lck.Lock(m_pSect);
		}
		eProtectEndTrace();
		xbSectLock lck(m_pSect);
		m_pTh = NULL;
	}

	virtual void	onStart(sIxbThread *pTh)
	{
		{
			xbSectLock lck(m_pSect);
			m_bCreateAsked = false;
			m_pTh = pTh;
			m_thId = ::GetCurrentThreadId();
		}
		pTh->StartCoInit();
	}
	virtual DWORD	onStop(sIxbThread *pTh,DWORD ret)
	{
		xbSectLock lck(m_pSect);
		if (!xbMustBe(pTh == m_pTh))
		{
			xbRelOutput("xbTThreadBase::onStop("+xbString(ret)+") : thread cb attached to another thread (stopped="+xbStrFromPtr(pTh)+", actual="+xbStrFromPtr(m_pTh)+")");
			return ret;
		}
		m_bCreateAsked = false;
		m_pTh = NULL;
		m_thId = 0;
		return ret;
	}
	virtual DWORD	onStopForce(sIxbThread *pTh,DWORD ret)
	{
		eProtectBegin();
		return onStop(pTh,ret);
		eProtectEndTrace();
		xbRelOutput("xbTThreadBase::onStopForce("+xbString(ret)+") : onStop failed");

		xbSectLock lck;
		eProtectTrace(lck.Lock(m_pSect););
		if (!xbMustBe(pTh == m_pTh))
		{
			xbRelOutput("xbTThreadBase::onStopForce("+xbString(ret)+") : thread cb attached to another thread (stopped="+xbStrFromPtr(pTh)+", actual="+xbStrFromPtr(m_pTh)+")");
			return ret;
		}
		m_bCreateAsked = false;
		m_pTh = NULL;
		return ret;
	}
	virtual bool	closeIfNotBusy(sIxbThread *pTh,xbLock *pThreadLckToUnlock,LPCSTR pReason)
	{
		xbSectLock lck(m_pSect);
		if (m_bBusy) return false;
		m_eventPtr.StopProcess();
		xbAssert(m_pTh == pTh);
		lck.Unlock();
		return pTh->Close(pThreadLckToUnlock,pReason,xbOp_Optional);
	}
	void setCloseReason(LPCSTR pReason)
	{
		xbSectLock lck(m_pSect);
		if (pReason && m_closeReason.IsEmpty())
			m_closeReason = pReason;
		xbRdbgAssert(m_eventPtr.ProcessToStop());
	}
	virtual xbThreadEventObject *GetThreadEvent() {return m_eventPtr;}
	virtual void onCloseAsked(sIxbThread *pTh,LPCSTR pReason)
	{
		setCloseReason(pReason);
	}

	
	xbSectShare	*m_pSect;
	xbString			m_label;
	bool				m_bBusy,m_bCreateAsked;
	sIxbThread			*m_pTh;
	xbString			m_closeReason;
	xbThreadEventPtr	m_eventPtr;
	ulong				m_thId;
};

class xbEXPORT xbThread:public xbTThreadBase<xbThreadCb>
{
public:
	xbThread(const xbString &label)
		:xbTThreadBase<xbThreadCb>(&m_sect,label)
	{
	}
protected:
	mutable xbSectShare	m_sect;
};

class xbEXPORT xbThreadMsg:public xbTThreadBase<xbThreadMsgCb>
{
public:
	xbThreadMsg(const xbString &label)
		:xbTThreadBase<xbThreadMsgCb>(&m_sect,label)
	{
	}
	void PostMessage( UINT message , WPARAM wParam, LPARAM lParam )
	{
		xbLock lckThread;
		GetThread(&lckThread)->PostMessage(message,wParam,lParam);
	}
protected:
	mutable xbSectShare	m_sect;
};


class xbEXPORT xbUseThreadCenter:public xbBase
{
public:
	xbUseThreadCenter()
	{
		m_pCenter = NULL;
	}
	xbUseThreadCenter(xbThreadCenter *pCenter,LPCSTR pThreadName = NULL)
	{
		m_pCenter = NULL;
		StartUse(pCenter,pThreadName);
	}
	~xbUseThreadCenter()
	{
		eProtectTrace(StopUse());
	}
	void StartUse(LPCSTR pThreadName = NULL)
	{
		StartUse(&g_xbThreadCenter,pThreadName);
	}
	void StartUse(xbThreadCenter *pCenter,LPCSTR pThreadName = NULL)
	{
		m_useCtx.Start(pThreadName);
		if (pCenter == m_pCenter) 
			return;
		if (m_pCenter) 
			StopUse();
		pCenter->threadUseLock();
		m_pCenter = pCenter;
	}
	void StopUse()
	{
		if (!m_pCenter) return;
		xbThreadCenter	*pCenter = m_pCenter;
		m_pCenter = NULL;
		pCenter->threadUseUnlock();
		m_useCtx.Stop();
	}
protected:
	xbUseThreadContext	m_useCtx;
	xbThreadCenter		*m_pCenter;

	xbDclNoNewForObject(xbUseThreadCenter);
	xbDclNoCopyForObject(xbUseThreadCenter);
};

class xbEXPORT xbUseEngineCenterExe:public xbUseEngineCenterBase
{
public:
	xbUseEngineCenterExe()
	{
	}
	xbUseEngineCenterExe(xbEngineCenter *pCenter,bool bStart,LPCSTR pThreadName = NULL)
		:xbUseEngineCenterBase()
	{
		StartUse(pCenter,bStart,pThreadName);
	}
	~xbUseEngineCenterExe()
	{
		eProtectTrace(StopUse());
	}
	virtual void StartUse(xbEngineCenter *pCenter,bool bStart,LPCSTR pThreadName = NULL)
	{
		xbUseEngineCenterBase::StartUse(pCenter,false,pThreadName);
		m_useTh.StartUse();
		if (bStart)
			m_pCenter->Start();
	}
	virtual void StopUse()
	{
		m_useTh.StopUse();
		xbUseEngineCenterBase::StopUse();
	}
protected:
	xbUseThreadCenter	m_useTh;
	xbDclNoNewForObject(xbUseEngineCenterExe);
	xbDclNoCopyForObject(xbUseEngineCenterExe);
};

xbEXPORT void xbThTrace(const xbString &txt);
xbEXPORT bool xbThToTrace();

#endif
