mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-06 22:39:55 +08:00
360 lines
8.3 KiB
C++
360 lines
8.3 KiB
C++
//
|
|
// Copyright (C) 2014 Novartis Institutes for BioMedical Research
|
|
//
|
|
// @@ All Rights Reserved @@
|
|
// This file is part of the RDKit.
|
|
// The contents are covered by the terms of the BSD license
|
|
// which is included in the file license.txt, found at the root
|
|
// of the RDKit source tree.
|
|
//
|
|
#pragma once
|
|
#ifndef __THREAD_H__INCLUDED
|
|
#define __THREAD_H__INCLUDED
|
|
/**
|
|
@file Thread.h
|
|
@brief Cross-platform (POSIX/Windows) thread.
|
|
*/
|
|
#ifdef WIN32
|
|
#include <windows.h>
|
|
#include <process.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <sys/time.h>
|
|
#endif
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include <string>
|
|
#include <cstring>
|
|
#include <stdio.h>
|
|
|
|
namespace RDKit
|
|
{
|
|
namespace FMCS
|
|
{
|
|
#ifndef WIN32 // POSIX.
|
|
static inline void Sleep(int ms)
|
|
{
|
|
struct timespec t;
|
|
t.tv_sec = ms/1000;
|
|
t.tv_nsec=(ms%1000)*1000000L;
|
|
while(-1==nanosleep(&t,&t) && errno==EINTR)
|
|
sleep(0);
|
|
sleep(0);
|
|
}
|
|
|
|
static inline void Sleep0()
|
|
{
|
|
usleep(0);
|
|
}
|
|
#else
|
|
static inline void Sleep0()
|
|
{
|
|
Sleep(0);
|
|
}
|
|
#endif
|
|
|
|
|
|
static inline long getThreadId() // move it to class Thread
|
|
{
|
|
#if defined(WIN32)
|
|
return (long)GetCurrentThreadId();
|
|
#elif defined(_POSIX_THREADS)
|
|
return (long)pthread_self();
|
|
#else
|
|
#error "You must define thread operations appropriate for your platform"
|
|
#endif
|
|
}
|
|
|
|
|
|
class SyncEvent;
|
|
|
|
class Mutex
|
|
{
|
|
private:
|
|
#ifdef WIN32
|
|
CRITICAL_SECTION mutex;
|
|
#else // POSIX compatible OS
|
|
pthread_mutex_t mutex;
|
|
friend class SyncEvent; // pthread_cond_timedwait() need access to mutex handle
|
|
#endif
|
|
|
|
public:
|
|
inline Mutex()
|
|
{
|
|
#ifdef WIN32
|
|
InitializeCriticalSection(&mutex);
|
|
#else // POSIX compatible OS
|
|
|
|
// MAC/SUN OS - default type is PTHREAD_MUTEX_NORMAL:
|
|
pthread_mutexattr_t attr;
|
|
pthread_mutexattr_init (&attr);
|
|
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
|
|
|
pthread_mutex_init(&mutex,&attr);
|
|
|
|
pthread_mutexattr_destroy(&attr);
|
|
//throw exception if error occured during initializing
|
|
#endif
|
|
}
|
|
|
|
inline ~Mutex()
|
|
{
|
|
#ifdef WIN32
|
|
DeleteCriticalSection(&mutex);
|
|
#else // POSIX compatible OS
|
|
pthread_mutex_destroy(&mutex);
|
|
#endif
|
|
}
|
|
|
|
inline bool lock()
|
|
{
|
|
#ifdef WIN32
|
|
EnterCriticalSection(&mutex);
|
|
return true;
|
|
#else // POSIX compatible OS
|
|
return 0==pthread_mutex_lock(&mutex);
|
|
#endif
|
|
}
|
|
|
|
inline bool trylock()
|
|
{
|
|
#ifdef WIN32
|
|
return TRUE==::TryEnterCriticalSection(&mutex); // NT only
|
|
#else // POSIX compatible OS
|
|
return 0==pthread_mutex_trylock(&mutex);
|
|
#endif
|
|
}
|
|
|
|
inline void unlock()
|
|
{
|
|
#ifdef WIN32
|
|
LeaveCriticalSection(&mutex);
|
|
#else // POSIX compatible OS
|
|
pthread_mutex_unlock(&mutex);
|
|
#endif
|
|
}
|
|
};
|
|
//---------------------------------------------------------------------
|
|
|
|
template<class SynchT=Mutex>
|
|
class Lock
|
|
{
|
|
SynchT& Synch;
|
|
public:
|
|
inline explicit Lock (SynchT& mutex) : Synch(mutex)
|
|
{
|
|
Synch.lock();
|
|
}
|
|
|
|
inline ~Lock ()
|
|
{
|
|
Synch.unlock();
|
|
}
|
|
};
|
|
|
|
typedef Lock<Mutex> Guard;
|
|
//---------------------------------------------------------------------
|
|
|
|
class Thread
|
|
{
|
|
#ifdef WIN32
|
|
HANDLE handle;
|
|
#else // POSIX compatible OS
|
|
pthread_t handle;
|
|
#endif
|
|
public:
|
|
inline Thread() : handle(0)
|
|
{
|
|
}
|
|
|
|
virtual ~Thread()
|
|
{
|
|
join();
|
|
handle = 0;
|
|
}
|
|
|
|
inline bool startThread(unsigned stackSize=0)
|
|
{
|
|
#ifdef WIN32
|
|
#ifdef _WIN32_WCE
|
|
DWORD id;
|
|
handle = CreateThread(NULL, stackSize, &Thread::_run, this, 0, &id);
|
|
if(NULL==handle)
|
|
return false;
|
|
#else
|
|
{
|
|
unsigned threadID;
|
|
handle = (HANDLE) _beginthreadex(NULL, stackSize, (unsigned int (__stdcall *)(void *)) &Thread::_run,this, 0, &threadID);
|
|
}
|
|
#endif
|
|
#else // POSIX compatible OS
|
|
pthread_attr_t attr;
|
|
pthread_attr_init(&attr);
|
|
if(0!=stackSize)
|
|
pthread_attr_setstacksize(&attr, stackSize);
|
|
int r = pthread_create(&handle, &attr, _run, this);
|
|
pthread_attr_destroy(&attr);
|
|
if(0 != r)
|
|
return false;
|
|
#endif
|
|
return true;
|
|
}
|
|
|
|
enum Priority
|
|
{
|
|
IDLE,
|
|
LOW,
|
|
NORMAL,
|
|
HIGH,
|
|
REALTIME
|
|
};
|
|
|
|
inline void setThreadPriority(Priority p)
|
|
{
|
|
#ifdef WIN32
|
|
int val[5] =
|
|
{
|
|
THREAD_PRIORITY_IDLE,
|
|
THREAD_PRIORITY_LOWEST,
|
|
THREAD_PRIORITY_NORMAL,
|
|
THREAD_PRIORITY_HIGHEST,
|
|
THREAD_PRIORITY_TIME_CRITICAL
|
|
};
|
|
SetThreadPriority(handle, val[p]);
|
|
#else // POSIX compatible OS
|
|
int policy, min_priority, max_priority;
|
|
struct sched_param param;
|
|
pthread_getschedparam(pthread_self(), &policy, ¶m);
|
|
min_priority = sched_get_priority_min(policy);
|
|
max_priority = sched_get_priority_max(policy);
|
|
switch(p)
|
|
{
|
|
default:
|
|
case IDLE:
|
|
param.sched_priority = min_priority;
|
|
break;
|
|
case LOW:
|
|
param.sched_priority = min_priority + (max_priority - min_priority) * 3/10;
|
|
break;
|
|
case NORMAL:
|
|
param.sched_priority = min_priority + (max_priority - min_priority) / 2;
|
|
break;
|
|
case HIGH:
|
|
param.sched_priority = min_priority + (max_priority - min_priority) * 9/10;
|
|
break;
|
|
case REALTIME:
|
|
param.sched_priority = max_priority;
|
|
break;
|
|
};
|
|
pthread_setschedparam(pthread_self(), policy, ¶m);
|
|
#endif
|
|
}
|
|
|
|
protected:
|
|
virtual void run(void)=0; // must be overriden
|
|
private:
|
|
static inline
|
|
#ifdef WIN32
|
|
#ifdef _WIN32_WCE
|
|
DWORD WINAPI _run(void *param)
|
|
#else
|
|
void _run(void *param)
|
|
#endif
|
|
#else // POSIX compatible OS
|
|
void* _run(void *param)
|
|
#endif
|
|
{
|
|
((Thread*)param)->run();
|
|
#if !defined(WIN32) || defined(_WIN32_WCE)
|
|
return 0;
|
|
#endif
|
|
}
|
|
public:
|
|
inline void join()
|
|
{
|
|
#ifdef WIN32
|
|
if(-1!=(int)handle && NULL!=handle && (handle))
|
|
{
|
|
WaitForSingleObject(handle,10*1000/*INFINITE*/); //!=WAIT_FAILED);
|
|
CloseHandle(handle);
|
|
handle = 0;
|
|
}
|
|
#else // POSIX compatible OS
|
|
void* exitcode;
|
|
if(0!=handle)
|
|
pthread_join(handle, &exitcode);
|
|
#endif
|
|
}
|
|
};
|
|
//---------------------------------------------------------------------
|
|
class SyncEvent
|
|
{
|
|
#ifdef WIN32
|
|
HANDLE handle;
|
|
#else // POSIX compatible OS
|
|
Mutex mutex;
|
|
pthread_cond_t condition;
|
|
bool signalled;
|
|
#endif
|
|
public:
|
|
inline SyncEvent()
|
|
{
|
|
#ifdef WIN32
|
|
handle = CreateEvent(0, FALSE, FALSE, 0);
|
|
#else // POSIX compatible OS
|
|
signalled = false;
|
|
pthread_cond_init(&condition, NULL);
|
|
#endif
|
|
}
|
|
|
|
inline ~SyncEvent()
|
|
{
|
|
#ifdef WIN32
|
|
CloseHandle(handle);
|
|
#else // POSIX compatible OS
|
|
pthread_cond_destroy(&condition);
|
|
#endif
|
|
}
|
|
|
|
inline bool wait(unsigned microseconds) // microseconds
|
|
{
|
|
#ifdef WIN32
|
|
return WAIT_OBJECT_0 == WaitForSingleObject(handle, microseconds/1000+(microseconds<1000 ? 1:0));
|
|
#else // POSIX compatible OS
|
|
struct timeval tv;
|
|
gettimeofday(&tv, (struct timezone*)0);
|
|
unsigned long long t = tv.tv_sec * 1000000ULL + tv.tv_usec + microseconds;
|
|
timespec timeout;
|
|
timeout.tv_sec = time_t(t/1000);
|
|
timeout.tv_nsec = long (t%1000 * 1000000UL);
|
|
mutex.lock();
|
|
while (!signalled)
|
|
if(ETIMEDOUT == pthread_cond_timedwait(&condition, &mutex.mutex, &timeout))
|
|
{
|
|
mutex.unlock();
|
|
return false;
|
|
}
|
|
signalled = false;
|
|
mutex.unlock();
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
inline void setSignal ()
|
|
{
|
|
#ifdef WIN32
|
|
SetEvent(handle);
|
|
#else // POSIX compatible OS
|
|
mutex.lock();
|
|
signalled = true;
|
|
mutex.unlock();
|
|
pthread_cond_signal(&condition);
|
|
#endif
|
|
}
|
|
};
|
|
//---------------------------------------------------------------------
|
|
}
|
|
}
|
|
#endif//__THREAD_H__INCLUDED
|