#ifndef MULTITHREAD_H
#define MULTITHREAD_H


#ifdef WIN32

// Thread functions under Windows

#include <windows.h>

typedef void * THREAD;

inline THREAD CreateNewThread(void * (*Function)(void *), void * Parameter)
{
  return CreateThread(0, 0, LPTHREAD_START_ROUTINE(Function), Parameter, 0, 0);
}

inline int KillThread(THREAD TheThread)
{
  return (TerminateThread(TheThread, 0));
}

inline int WaitThread(THREAD TheThread)
{
  int ReturnValue;
  WaitForSingleObject(TheThread, INFINITE);
  GetExitCodeThread(TheThread, (LPDWORD) &ReturnValue);
  CloseHandle(TheThread);
  return ReturnValue;
}

inline void DetachThread(THREAD TheThread)
{
  CloseHandle(TheThread);
}

inline void ExitCurrentThread(int ReturnValue)
{
  ExitThread(ReturnValue);
}


class Mutex
{
  CRITICAL_SECTION lock;

 public:
  Mutex(void) { InitializeCriticalSection(&lock); }
  ~Mutex(void) { DeleteCriticalSection(&lock); }
  void Lock(void) { EnterCriticalSection(&lock); }
  void Unlock(void) { LeaveCriticalSection(&lock); }
};

class Semaphore
{
  HANDLE lock;

 public:
  Semaphore(int value) { lock = CreateSemaphore(0, value, 0x7fffffff, 0); }
  ~Semaphore() { CloseHandle(lock); }
  void Wait() { WaitForSingleObject(lock, INFINITE); }
  void Post() { ReleaseSemaphore(lock,1,0); }
};

// End of the thread functions under Windows



#elif defined __linux__

// Thread functions under Linux

#include <pthread.h>
#include <semaphore.h>

typedef pthread_t THREAD;

inline THREAD CreateNewThread(void * (*Function)(void *), void * Parameter)
{
  pthread_t TheThread;
  pthread_create(&TheThread, 0, Function, Parameter);
  return (THREAD) TheThread;
}

inline int KillThread(THREAD TheThread)
{
  return !(pthread_cancel(TheThread));
}

inline int WaitThread(THREAD TheThread)
{
  int ReturnValue;
  pthread_join(TheThread, reinterpret_cast<void**> (&ReturnValue));
  return ReturnValue;
}

inline void DetachThread(THREAD TheThread)
{
  pthread_detach(TheThread);
}

inline void ExitCurrentThread(int ReturnValue)
{
  pthread_exit(reinterpret_cast<void *> (ReturnValue));
}


class Mutex
{
  pthread_mutex_t lock;

 public:
  Mutex() { pthread_mutex_init(&lock, 0); }
  ~Mutex() { pthread_mutex_destroy(&lock); }
  void Lock(void) { pthread_mutex_lock(&lock); }
  void Unlock(void) { pthread_mutex_unlock(&lock); }
};

class Semaphore
{
  sem_t lock;

 public:
  Semaphore(int value = 0) { sem_init(&lock, 0, value); }
  ~Semaphore() { sem_destroy(&lock); }
  void Wait() { sem_wait(&lock); }
  void Post() { sem_post(&lock); }
};

// End of the thread functions under Linux

#else

#error ERROR: OS not supported



#endif

#endif
