xgboost/old_src/utils/thread.h
2016-01-16 10:24:00 -08:00

261 lines
6.0 KiB
C++

/*!
* Copyright by Contributors
* \file thread.h
* \brief this header include the minimum necessary resource
* for multi-threading that can be compiled in windows, linux, mac
* \author Tianqi Chen
*/
#ifndef XGBOOST_UTILS_THREAD_H_ // NOLINT(*)
#define XGBOOST_UTILS_THREAD_H_ // NOLINT(*)
#ifdef _MSC_VER
#include <windows.h>
#include <process.h>
#include "./utils.h"
namespace xgboost {
namespace utils {
/*! \brief simple semaphore used for synchronization */
class Semaphore {
public :
inline void Init(int init_val) {
sem = CreateSemaphore(NULL, init_val, 10, NULL);
utils::Check(sem != NULL, "create Semaphore error");
}
inline void Destroy(void) {
CloseHandle(sem);
}
inline void Wait(void) {
utils::Check(WaitForSingleObject(sem, INFINITE) == WAIT_OBJECT_0, "WaitForSingleObject error");
}
inline void Post(void) {
utils::Check(ReleaseSemaphore(sem, 1, NULL) != 0, "ReleaseSemaphore error");
}
private:
HANDLE sem;
};
/*! \brief mutex under windows */
class Mutex {
public:
inline void Init(void) {
utils::Check(InitializeCriticalSectionAndSpinCount(&mutex, 0x00000400) != 0,
"Mutex::Init fail");
}
inline void Lock(void) {
EnterCriticalSection(&mutex);
}
inline void Unlock(void) {
LeaveCriticalSection(&mutex);
}
inline void Destroy(void) {
DeleteCriticalSection(&mutex);
}
private:
friend class ConditionVariable;
CRITICAL_SECTION mutex;
};
// conditional variable that uses pthread
class ConditionVariable {
public:
// initialize conditional variable
inline void Init(void) {
InitializeConditionVariable(&cond);
}
// destroy the thread
inline void Destroy(void) {
// DeleteConditionVariable(&cond);
}
// wait on the conditional variable
inline void Wait(Mutex *mutex) {
utils::Check(SleepConditionVariableCS(&cond, &(mutex->mutex), INFINITE) != 0,
"ConditionVariable:Wait fail");
}
inline void Broadcast(void) {
WakeAllConditionVariable(&cond);
}
inline void Signal(void) {
WakeConditionVariable(&cond);
}
private:
CONDITION_VARIABLE cond;
};
/*! \brief simple thread that wraps windows thread */
class Thread {
private:
HANDLE thread_handle;
unsigned thread_id;
public:
inline void Start(unsigned int __stdcall entry(void*p), void *param) {
thread_handle = (HANDLE)_beginthreadex(NULL, 0, entry, param, 0, &thread_id);
}
inline int Join(void) {
WaitForSingleObject(thread_handle, INFINITE);
return 0;
}
};
/*! \brief exit function called from thread */
inline void ThreadExit(void *status) {
_endthreadex(0);
}
#define XGBOOST_THREAD_PREFIX unsigned int __stdcall
} // namespace utils
} // namespace xgboost
#else
// thread interface using g++
#include <semaphore.h>
#include <pthread.h>
#include <errno.h>
namespace xgboost {
namespace utils {
/*!\brief semaphore class */
class Semaphore {
#ifdef __APPLE__
private:
sem_t* semPtr;
char sema_name[20];
private:
inline void GenRandomString(char *s, const int len) {
static const char alphanum[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (int i = 0; i < len; ++i) {
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
}
s[len] = 0;
}
public:
inline void Init(int init_val) {
sema_name[0] = '/';
sema_name[1] = 's';
sema_name[2] = 'e';
sema_name[3] = '/';
GenRandomString(&sema_name[4], 16);
if ((semPtr = sem_open(sema_name, O_CREAT, 0644, init_val)) == SEM_FAILED) {
perror("sem_open");
exit(1);
}
utils::Check(semPtr != NULL, "create Semaphore error");
}
inline void Destroy(void) {
if (sem_close(semPtr) == -1) {
perror("sem_close");
exit(EXIT_FAILURE);
}
if (sem_unlink(sema_name) == -1) {
perror("sem_unlink");
exit(EXIT_FAILURE);
}
}
inline void Wait(void) {
sem_wait(semPtr);
}
inline void Post(void) {
sem_post(semPtr);
}
#else
private:
sem_t sem;
public:
inline void Init(int init_val) {
if (sem_init(&sem, 0, init_val) != 0) {
utils::Error("Semaphore.Init:%s", strerror(errno));
}
}
inline void Destroy(void) {
if (sem_destroy(&sem) != 0) {
utils::Error("Semaphore.Destroy:%s", strerror(errno));
}
}
inline void Wait(void) {
if (sem_wait(&sem) != 0) {
utils::Error("Semaphore.Wait:%s", strerror(errno));
}
}
inline void Post(void) {
if (sem_post(&sem) != 0) {
utils::Error("Semaphore.Post:%s", strerror(errno));
}
}
#endif
};
// mutex that works with pthread
class Mutex {
public:
inline void Init(void) {
pthread_mutex_init(&mutex, NULL);
}
inline void Lock(void) {
pthread_mutex_lock(&mutex);
}
inline void Unlock(void) {
pthread_mutex_unlock(&mutex);
}
inline void Destroy(void) {
pthread_mutex_destroy(&mutex);
}
private:
friend class ConditionVariable;
pthread_mutex_t mutex;
};
// conditional variable that uses pthread
class ConditionVariable {
public:
// initialize conditional variable
inline void Init(void) {
pthread_cond_init(&cond, NULL);
}
// destroy the thread
inline void Destroy(void) {
pthread_cond_destroy(&cond);
}
// wait on the conditional variable
inline void Wait(Mutex *mutex) {
pthread_cond_wait(&cond, &(mutex->mutex));
}
inline void Broadcast(void) {
pthread_cond_broadcast(&cond);
}
inline void Signal(void) {
pthread_cond_signal(&cond);
}
private:
pthread_cond_t cond;
};
/*!\brief simple thread class */
class Thread {
private:
pthread_t thread;
public :
inline void Start(void * entry(void*), void *param) { // NOLINT(*)
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&thread, &attr, entry, param);
}
inline int Join(void) {
void *status;
return pthread_join(thread, &status);
}
};
inline void ThreadExit(void *status) {
pthread_exit(status);
}
} // namespace utils
} // namespace xgboost
#define XGBOOST_THREAD_PREFIX void *
#endif // Linux
#endif // XGBOOST_UTILS_THREAD_H_ NOLINT(*)