#ifndef THREAD__H_ #define THREAD__H_ #ifndef COMMON__H_ #include "common.h" #endif #ifdef _WIN32 #pragma once #else #include #include //#include //#define WAIT_NEW_VER_ #endif // WIN32 #ifdef _WIN32 #define pthread_self GetCurrentThreadId #else #define GetCurrentThreadId pthread_self #endif // _WIN32 class HSyncObject : public HObject { public: HSyncObject() { #ifdef _WIN32 InitializeCriticalSection(&m_instance); #else pthread_mutex_init(&m_instance, NULL); #endif // _WIN32 } virtual ~HSyncObject() { #ifdef _WIN32 DeleteCriticalSection(&m_instance); #else pthread_mutex_destroy(&m_instance); #endif // _WIN32 } bool IsLocked(); int Lock(); int Unlock(); protected: #ifdef _WIN32 CRITICAL_SECTION m_instance; #else pthread_mutex_t m_instance; #endif }; inline int HSyncObject::Lock() { #ifdef _WIN32 EnterCriticalSection(&m_instance); return 0; #else return pthread_mutex_lock(&m_instance); #endif // WIN32 } inline int HSyncObject::Unlock() { #ifdef _WIN32 LeaveCriticalSection(&m_instance); return 0; #else return pthread_mutex_unlock(&m_instance); #endif // WIN32 } /////////////////////////////////////// class HAutoLock : public HObject { public: HAutoLock(HSyncObject * pObject) : m_pObject(pObject) { m_pObject->Lock(); } ~HAutoLock() { m_pObject->Unlock(); } private: HSyncObject * m_pObject; }; class HSyncEvent : public HObject { public: HSyncEvent(bool bManualReset = false, bool bInitialState = false) { #ifdef _WIN32 m_hEvent = CreateEvent(NULL, bManualReset, bInitialState, NULL); #else pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_cond, NULL); m_bManualReset = bManualReset; if (bInitialState) m_bEventSet = true; #endif // _WIN32 } ~HSyncEvent() { #ifdef _WIN32 CloseHandle(m_hEvent); #else pthread_cond_destroy(&m_cond); pthread_mutex_destroy(&m_mutex); #endif // _WIN32 } bool SetEvent() { #ifdef _WIN32 return ::SetEvent(m_hEvent) != false; #else pthread_mutex_lock(&m_mutex); m_bEventSet = true; pthread_cond_signal(&m_cond); pthread_mutex_unlock(&m_mutex); #endif // _WIN32 return true; } bool ResetEvent() { #ifdef _WIN32 return ::ResetEvent(m_hEvent) != false; #else pthread_mutex_lock(&m_mutex); m_bEventSet = false; pthread_mutex_unlock(&m_mutex); #endif // _WIN32 return true; } bool Wait(DWORD dwWaitTime) // dwTimeout : msec { #ifdef _WIN32 if (WaitForSingleObject(m_hEvent, dwWaitTime) == WAIT_TIMEOUT) return false; #else struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) return true; ts.tv_sec += dwWaitTime / 1000; // seconds ts.tv_nsec += (dwWaitTime % 1000) * 1000000; // nanoseconds pthread_mutex_lock(&m_mutex); if (m_bEventSet) { pthread_mutex_unlock(&m_mutex); if (m_bManualReset == false) m_bEventSet = false; return true; } int nResult = pthread_cond_timedwait(&m_cond, &m_mutex, &ts); pthread_mutex_unlock(&m_mutex); if (nResult == ETIMEDOUT) return false; if (m_bManualReset == false) m_bEventSet = false; #endif // _WIN32 return true; } private: #ifdef _WIN32 HANDLE m_hEvent; #else pthread_mutex_t m_mutex; pthread_cond_t m_cond; bool m_bManualReset; volatile bool m_bEventSet; #endif // _WIN32 }; class HThread : public HObject { public: HThread(bool bAutoDelete = false, size_t nStackSize = 0) : m_bAutoDelete(bAutoDelete) , m_nStackSize(nStackSize) { #ifdef _WIN32 m_hThread = NULL; #else m_tId = 0; #ifndef WAIT_NEW_VER_ pthread_mutex_init(&m_mutex, NULL); pthread_cond_init(&m_cond, NULL); #endif #endif // WIN32 } ~HThread() {} #ifdef _WIN32 inline HANDLE GetThreadId() { return m_hThread; } #else inline pthread_t GetThreadId() { return m_tId; } #endif virtual inline unsigned long Begin(); bool WaitForTermination(DWORD dwWaitTime) { #ifdef _WIN32 if (m_hThread == NULL) return true; if (WaitForSingleObject(m_hThread, dwWaitTime) == WAIT_TIMEOUT) return false; #else if (m_tId == 0) return true; struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) return true; ts.tv_sec += dwWaitTime / 1000; // seconds ts.tv_nsec += (dwWaitTime % 1000) * 1000000; // nanoseconds #ifndef WAIT_NEW_VER_ pthread_mutex_lock(&m_mutex); int nResult = pthread_cond_timedwait(&m_cond, &m_mutex, &ts); pthread_mutex_unlock(&m_mutex); if (nResult == ETIMEDOUT) return false; #else if (pthread_timedjoin_np(m_tId, NULL, &ts) == ETIMEDOUT) return false; #endif // WAIT_NEW_VER_ #endif // WIN32 return true; } #if !defined(__ANDROID__) && !defined(ANDROID) void TerminateThread(DWORD dwExitCode = 0) { #ifdef _WIN32 if (m_hThread == NULL) return; ::TerminateThread(m_hThread, dwExitCode); CloseHandle(m_hThread); m_hThread = NULL; #else if (m_tId == 0) return; pthread_cancel(m_tId); m_tId = 0; #endif } #endif // protected: virtual void Main() = 0; virtual void OnTerminated() {} #ifdef _WIN32 inline static DWORD WINAPI #else inline static void * #endif BeginThread(void * lpParameter); private: void MainCallBack(); private: bool m_bAutoDelete; size_t m_nStackSize; // bytes #ifdef _WIN32 HANDLE m_hThread; #else pthread_t m_tId; #ifndef WAIT_NEW_VER_ pthread_mutex_t m_mutex; pthread_cond_t m_cond; #endif #endif }; inline unsigned long HThread::Begin() { #ifdef _WIN32 DWORD dwThreadId; if ((m_hThread = ::CreateThread(NULL, m_nStackSize, BeginThread, this, 0, &dwThreadId)) == NULL) return ::GetLastError(); return 0; #else if (m_nStackSize > 0) { pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, m_nStackSize); #if 0 // do not use pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); #endif int nResult = pthread_create(&m_tId, &attr, BeginThread, (void *)this); pthread_attr_destroy(&attr); return nResult; } return pthread_create(&m_tId, NULL, BeginThread, (void *)this); #endif // WIN32 } #ifdef _WIN32 inline DWORD WINAPI #else inline void * #endif HThread::BeginThread(void * lpParameter) { ((HThread *)lpParameter)->MainCallBack(); return NULL; } inline void HThread::MainCallBack() { Main(); #ifndef _WIN32 #ifndef WAIT_NEW_VER_ pthread_mutex_lock(&m_mutex); pthread_cond_broadcast(&m_cond); pthread_mutex_unlock(&m_mutex); #endif // WAIT_NEW_VER_ pthread_detach(m_tId); #endif OnTerminated(); if (m_bAutoDelete) delete this; } /////////////////////////////////////// class HThreadExecuter : public HThread { public: HThreadExecuter() { m_fnThreadMainCallBack = NULL; m_pThreadMainParam = NULL; m_fnExitThreadCallBack = NULL; m_pOnExitThreadParam = NULL; } HThreadExecuter(bool bAutoDelete, size_t nStackSize) : HThread(bAutoDelete, nStackSize) { m_fnThreadMainCallBack = NULL; m_pThreadMainParam = NULL; m_fnExitThreadCallBack = NULL; m_pOnExitThreadParam = NULL; } ~HThreadExecuter() { m_fnThreadMainCallBack = NULL; m_pThreadMainParam = NULL; m_fnExitThreadCallBack = NULL; m_pOnExitThreadParam = NULL; } inline void Initialize(void (*fnThreadMainCallBack)(void * pThreadParameter), // thread main procedure void * pThreadMainParam, // parmeter for thread main void (*fnExitThreadCallBack)(void * pThreadParameter), // terminated thread call back void * pOnExitThreadParam) // parmeter for terminated thread { m_fnThreadMainCallBack = fnThreadMainCallBack; m_pThreadMainParam = pThreadMainParam; m_fnExitThreadCallBack = fnExitThreadCallBack; m_pOnExitThreadParam = pOnExitThreadParam; } protected: inline void Main() { if (m_fnThreadMainCallBack) m_fnThreadMainCallBack(m_pThreadMainParam); } inline void OnTerminated() { if (m_fnExitThreadCallBack) m_fnExitThreadCallBack(m_pOnExitThreadParam); } protected: void (*m_fnThreadMainCallBack)(void * pThreadParameter); void * m_pThreadMainParam; void (*m_fnExitThreadCallBack)(void * pThreadParameter); void * m_pOnExitThreadParam; }; /* protected: // $(Name) thread part static inline void $(Name)ThreadCallBack(void * pParam) { return static_cast<$(ClassName) *>(pParam)->$(Name)ThreadMain(); } static inline void $(Name)ThreadTerminatedCallBack(void * pParam) { static_cast<$(ClassName) *>(pParam)->On$(Name)ThreadTerminated(); } void $(Name)ThreadMain(); void On$(Name)ThreadTerminated(); HThreadExecuter * m_p$(Name)Thread; // m_p$(Name)Thread = new HThreadExecuter(); m_p$(Name)Thread->Initialize($(Name)ThreadCallBack, this, $(Name)ThreadTerminatedCallBack, this); m_p$(Name)Thread->Begin(); delete m_p$(Name)Thread; */ #endif // THREAD__H_