You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

435 lines
13 KiB

////////////////////////////////////////////////////////////////////
// Thread.h
//
// Copyright 2007 cDc@seacave
// Distributed under the Boost Software License, Version 1.0
// (See http://www.boost.org/LICENSE_1_0.txt)
#ifndef __SEACAVE_THREAD_H__
#define __SEACAVE_THREAD_H__
// I N C L U D E S /////////////////////////////////////////////////
#ifdef _MSC_VER
#include <windows.h>
#ifdef _SUPPORT_CPP11
#include <cstdint>
#else
#include <stdint.h>
#endif
#else
#include <pthread.h>
#include <sched.h>
#include <sys/resource.h>
#include <unistd.h>
#endif
// D E F I N E S ///////////////////////////////////////////////////
namespace SEACAVE {
// S T R U C T S ///////////////////////////////////////////////////
/**************************************************************************************
* Thread
* --------------
* basic thread control
**************************************************************************************/
class GENERAL_API Thread
{
public:
#ifdef _ENVIRONMENT64
typedef int64_t safe_t;
#else
typedef int32_t safe_t;
#endif
enum Priority {
IDLE = -2,
LOW = -1,
NORMAL = 0,
HIGH = 1
};
#ifdef _MSC_VER
typedef HANDLE thread_t;
typedef void* (STCALL *FncStart)(void*);
typedef struct STARTER_DATA {
FncStart fnStarter;
void* pData;
STARTER_DATA(FncStart _fnStarter, void* _pData) : fnStarter(_fnStarter), pData(_pData) {}
} StarterData;
Thread() : threadHandle(NULL), threadId(0) {}
virtual ~Thread() { stop(); }
inline bool isRunning() const { return (threadHandle != NULL); }
bool start(FncStart pfnStarter, void* pData=NULL) {
join();
return ((threadHandle = CreateThread(NULL, 0, &starterConvertor, new StarterData(pfnStarter, pData), 0, &threadId)) != NULL);
}
inline bool start() {
return start(&starter, this);
}
void stop() {
if (threadHandle) {
TerminateThread(threadHandle, -1);
CloseHandle(threadHandle);
threadHandle = NULL;
threadId = 0;
}
}
void join() {
if (threadHandle == NULL)
return;
WaitForSingleObject(threadHandle, INFINITE);
CloseHandle(threadHandle);
threadHandle = NULL;
threadId = 0;
}
inline void setThreadPriority(Priority p) const { ::SetThreadPriority(threadHandle, convertPriority(p)); }
inline Priority getThreadPriority() const { return convertPriority((PriorityOS)::GetThreadPriority(threadHandle)); }
static inline void setThreadPriority(thread_t th, Priority p) { ::SetThreadPriority(th, convertPriority(p)); }
static inline Priority getThreadPriority(thread_t th) { return convertPriority((PriorityOS)::GetThreadPriority(th)); }
static inline void sleep(uint32_t millis) { ::Sleep(millis); }
static inline void yield() { ::Sleep(0); }
static inline thread_t currentThread() { return ::GetCurrentThread(); }
static uint32_t hardwareConcurrency() {
SYSTEM_INFO info={{0}};
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
}
STATIC_ASSERT(sizeof(int32_t)==sizeof(LONG));
static inline int32_t safeInc(volatile int32_t& v) { return InterlockedIncrement((volatile LONG*)&v); };
static inline int32_t safeDec(volatile int32_t& v) { return InterlockedDecrement((volatile LONG*)&v); };
static inline int32_t safeExchange(volatile int32_t& target, int32_t value) { return InterlockedExchange((volatile LONG*)&target, value); };
static inline int32_t safeCompareExchange(volatile int32_t& target, int32_t comp, int32_t value) { return InterlockedCompareExchange((volatile LONG*)&target, value, comp); };
STATIC_ASSERT(sizeof(int64_t)==sizeof(LONGLONG));
static inline int64_t safeInc(volatile int64_t& v) { return InterlockedIncrement64((volatile LONGLONG*)&v); };
static inline int64_t safeDec(volatile int64_t& v) { return InterlockedDecrement64((volatile LONGLONG*)&v); };
static inline int64_t safeExchange(volatile int64_t& target, int64_t value) { return InterlockedExchange64((volatile LONGLONG*)&target, value); };
static inline int64_t safeCompareExchange(volatile int64_t& target, int64_t comp, int64_t value) { return InterlockedCompareExchange64((volatile LONGLONG*)&target, value, comp); };
#else //_MSC_VER
typedef pthread_t thread_t;
typedef void* (STCALL *FncStart)(void*);
Thread() : threadHandle(0) {}
virtual ~Thread() { stop(); }
inline bool isRunning() const { return (threadHandle != 0); }
bool start(FncStart pfnStarter, void* pData=NULL) {
join();
return (pthread_create(&threadHandle, NULL, pfnStarter, pData) == 0);
}
bool start() {
return start(&starter, this);
}
void stop() {
if (threadHandle != 0) {
pthread_detach(threadHandle);
threadHandle = 0;
}
}
void join() {
if (threadHandle) {
pthread_join(threadHandle, 0);
threadHandle = 0;
}
}
inline void setThreadPriority(Priority p) const { setThreadPriority(threadHandle, p); }
inline Priority getThreadPriority() const { return getThreadPriority(threadHandle); }
static void setThreadPriority(thread_t th, Priority p) {
struct sched_param param;
param.sched_priority = convertPriority(p);
pthread_setschedparam(th, SCHED_OTHER, &param);
}
static Priority getThreadPriority(thread_t th) {
struct sched_param param;
int policy;
pthread_getschedparam(th, &policy, &param);
return convertPriority((PriorityOS)param.sched_priority);
}
static void sleep(uint32_t millis) { ::usleep(millis*1000); }
static void yield() { ::sched_yield(); }
static inline thread_t currentThread(){ return pthread_self(); }
static uint32_t hardwareConcurrency() { return sysconf(_SC_NPROCESSORS_ONLN); }
static inline int32_t safeInc(volatile int32_t& v) { return __sync_add_and_fetch(&v, 1); }
static inline int32_t safeDec(volatile int32_t& v) { return __sync_sub_and_fetch(&v, 1); }
static inline int32_t safeExchange(volatile int32_t& target, int32_t value) { return __sync_val_compare_and_swap(&target, target, value); }
static inline int32_t safeCompareExchange(volatile int32_t& target, int32_t comp, int32_t value) { return __sync_val_compare_and_swap(&target, comp, value); }
static inline int64_t safeInc(volatile int64_t& v) { return __sync_add_and_fetch(&v, 1); }
static inline int64_t safeDec(volatile int64_t& v) { return __sync_sub_and_fetch(&v, 1); }
static inline int64_t safeExchange(volatile int64_t& target, int64_t value) { return __sync_val_compare_and_swap(&target, target, value); }
static inline int64_t safeCompareExchange(volatile int64_t& target, int64_t comp, int64_t value) { return __sync_val_compare_and_swap(&target, comp, value); }
#endif //_MSC_VER
static unsigned getMaxThreads(unsigned threads) {
if (threads == 1)
return 1;
const unsigned maxThreads = hardwareConcurrency();
if (threads > 0 && threads < maxThreads)
return threads;
return maxThreads;
}
protected:
virtual void run() {}
protected:
#ifdef _MSC_VER
enum PriorityOS {
OS_IDLE = THREAD_PRIORITY_IDLE,
OS_LOW = THREAD_PRIORITY_BELOW_NORMAL,
OS_NORMAL = THREAD_PRIORITY_NORMAL,
OS_HIGH = THREAD_PRIORITY_ABOVE_NORMAL
};
static DWORD WINAPI starterConvertor(void* p)
{
CAutoPtr<StarterData> pData((StarterData*)p);
return (DWORD)reinterpret_cast<size_t>(pData->fnStarter(pData->pData));
}
#else //_MSC_VER
enum PriorityOS {
OS_IDLE = 19,
OS_LOW = 10,
OS_NORMAL = 0,
OS_HIGH = -10
};
#endif //_MSC_VER
static inline PriorityOS convertPriority(Priority p) {
switch (p) {
case IDLE: return OS_IDLE;
case LOW: return OS_LOW;
case NORMAL: return OS_NORMAL;
case HIGH: return OS_HIGH;
}
return OS_NORMAL;
}
static inline Priority convertPriority(PriorityOS p) {
switch (p) {
case OS_IDLE: return IDLE;
case OS_LOW: return LOW;
case OS_NORMAL: return NORMAL;
case OS_HIGH: return HIGH;
}
return NORMAL;
}
static void* starter(void* p)
{
((Thread*)p)->run();
return NULL;
}
protected:
thread_t threadHandle;
#ifdef _MSC_VER
DWORD threadId;
#endif
};
/*----------------------------------------------------------------*/
/**************************************************************************************
* ThreadPool
* --------------
* basic thread pool
**************************************************************************************/
class GENERAL_API ThreadPool
{
public:
typedef uint32_t size_type;
typedef Thread value_type;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef CLISTDEFIDX(Thread,size_type) Threads;
public:
inline ThreadPool() {}
inline ThreadPool(size_type nThreads) : _threads(nThreads>0?nThreads:Thread::hardwareConcurrency()) {}
inline ThreadPool(size_type nThreads, Thread::FncStart pfnStarter, void* pData=NULL) : _threads(nThreads>0?nThreads:Thread::hardwareConcurrency()) { start(pfnStarter, pData); }
inline ~ThreadPool() { join(); }
#ifdef _SUPPORT_CPP11
inline ThreadPool(ThreadPool&& rhs) : _threads(std::forward<Threads>(rhs._threads)) {
}
inline ThreadPool& operator=(ThreadPool&& rhs) {
_threads.Swap(rhs._threads);
return *this;
}
#endif
// wait for all running threads to finish and resize threads array
void resize(size_type nThreads) {
join();
_threads.resize(nThreads);
}
// start all threads with the given function
bool start(Thread::FncStart pfnStarter, void* pData=NULL) {
for (Thread& thread: _threads)
if (!thread.start(pfnStarter, pData))
return false;
return true;
}
// wait for all running threads to finish
void join() {
for (Thread& thread: _threads)
thread.join();
}
// stop all threads
void stop() {
for (Thread& thread: _threads)
thread.stop();
}
// wait for all running threads to finish and release threads array
void Release() {
join();
_threads.Release();
}
inline bool empty() const { return _threads.empty(); }
inline size_type size() const { return _threads.size(); }
inline const_iterator cbegin() const { return _threads.cbegin(); }
inline const_iterator cend() const { return _threads.cend(); }
inline const_iterator begin() const { return _threads.begin(); }
inline const_iterator end() const { return _threads.end(); }
inline iterator begin() { return _threads.begin(); }
inline iterator end() { return _threads.end(); }
inline const_reference operator[](size_type index) const { return _threads[index]; }
inline reference operator[](size_type index) { return _threads[index]; }
protected:
Threads _threads;
};
/*----------------------------------------------------------------*/
/**************************************************************************************
* Process
* --------------
* basic process control
**************************************************************************************/
class GENERAL_API Process
{
public:
enum Priority {
IDLE = -3,
LOW = -2,
BELOWNORMAL = -1,
NORMAL = 0,
ABOVENORMAL = 1,
HIGH = 2,
REALTIME = 3
};
#ifdef _MSC_VER
typedef HANDLE process_t;
static inline process_t getCurrentProcessID() { return ::GetCurrentProcess(); }
static inline void setProcessPriority(process_t id, Priority p) { ::SetPriorityClass(id, convertPriority(p)); }
static inline Priority getProcessPriority(process_t id) { return convertPriority((PriorityOS)::GetPriorityClass(id)); }
#else //_MSC_VER
typedef id_t process_t;
static inline process_t getCurrentProcessID() { return ::getpid(); }
static inline void setProcessPriority(process_t id, Priority p) { ::setpriority(PRIO_PROCESS, id, convertPriority(p)); }
static inline Priority getProcessPriority(process_t id) { return convertPriority((PriorityOS)::getpriority(PRIO_PROCESS, id)); }
#endif //_MSC_VER
static inline void setCurrentProcessPriority(Priority p) { setProcessPriority(getCurrentProcessID(), p); }
static inline Priority getCurrentProcessPriority() { return getProcessPriority(getCurrentProcessID()); }
protected:
#ifdef _MSC_VER
enum PriorityOS {
OS_IDLE = IDLE_PRIORITY_CLASS,
OS_LOW = PROCESS_MODE_BACKGROUND_BEGIN,
OS_BELOWNORMAL = BELOW_NORMAL_PRIORITY_CLASS,
OS_NORMAL = NORMAL_PRIORITY_CLASS,
OS_ABOVENORMAL = ABOVE_NORMAL_PRIORITY_CLASS,
OS_HIGH = HIGH_PRIORITY_CLASS,
OS_REALTIME = REALTIME_PRIORITY_CLASS
};
#else //_MSC_VER
enum PriorityOS {
OS_IDLE = 19,
OS_LOW = 15,
OS_BELOWNORMAL = 10,
OS_NORMAL = 0,
OS_ABOVENORMAL = -10,
OS_HIGH = -15,
OS_REALTIME = -20
};
#endif //_MSC_VER
static inline PriorityOS convertPriority(Priority p) {
switch (p) {
case IDLE: return OS_IDLE;
case LOW: return OS_LOW;
case BELOWNORMAL: return OS_BELOWNORMAL;
case NORMAL: return OS_NORMAL;
case ABOVENORMAL: return OS_ABOVENORMAL;
case HIGH: return OS_HIGH;
case REALTIME: return OS_REALTIME;
}
return OS_NORMAL;
}
static inline Priority convertPriority(PriorityOS p) {
switch (p) {
case OS_IDLE: return IDLE;
case OS_LOW: return LOW;
case OS_BELOWNORMAL: return BELOWNORMAL;
case OS_NORMAL: return NORMAL;
case OS_ABOVENORMAL: return ABOVENORMAL;
case OS_HIGH: return HIGH;
case OS_REALTIME: return REALTIME;
}
return NORMAL;
}
};
/*----------------------------------------------------------------*/
} // namespace SEACAVE
#endif // __SEACAVE_THREAD_H__