454 lines
8.5 KiB
C++
454 lines
8.5 KiB
C++
|
|
#ifndef THREAD__H_
|
|
#define THREAD__H_
|
|
|
|
|
|
#ifndef COMMON__H_
|
|
#include "common.h"
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
|
|
#pragma once
|
|
|
|
#else
|
|
|
|
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
//#include <signal.h>
|
|
|
|
//#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;
|
|
};
|
|
/*
|
|
<below add to .h file>
|
|
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;
|
|
//
|
|
|
|
|
|
<add to constructor>
|
|
m_p$(Name)Thread = new HThreadExecuter();
|
|
m_p$(Name)Thread->Initialize($(Name)ThreadCallBack, this, $(Name)ThreadTerminatedCallBack, this);
|
|
m_p$(Name)Thread->Begin();
|
|
|
|
<add to destructor or termination code>
|
|
delete m_p$(Name)Thread;
|
|
*/
|
|
#endif // THREAD__H_
|