Files
smartservice_native/hdssd/huslib/Thread.h
T
2026-05-20 03:08:08 +09:00

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_