Files
2018-07-17 14:15:37 +02:00

266 lines
5.0 KiB
C++

#pragma once
#ifdef _MSC_VER
#define Threaded(type) __declspec(thread) type
#define threadcall __stdcall
#else
#include <atomic>
#include <pthread.h>
#define Threaded(type) __thread type
#define threadcall
#endif
//#define PROFILE_LOCKS
#ifdef PROFILE_LOCKS
#include <string>
#include <set>
#endif
#include <functional>
namespace threads {
unsigned getNumberOfProcessors();
void async(std::function<int()> f);
void sleep(unsigned int milliseconds);
//Sleep intended for use as a wait in a non-critical busy loop
void idle();
#ifndef _MSC_VER
typedef unsigned int threadreturn;
typedef threadreturn (*threadfunc)(void*);
#else
typedef unsigned long threadreturn;
typedef threadreturn threadcall threadfunc(void*);
#endif
class atomic_int {
#ifdef _MSC_VER
volatile long value;
#else
volatile int value;
#endif
public:
int get_basic();
void set_basic(int val);
int operator++();
int operator++(int);
int operator--();
int operator--(int);
int operator+=(int value);
int operator-=(int value);
int operator|=(int value);
int operator&=(int value);
void operator=(int value);
int exchange(int value);
int compare_exchange_strong(int value, int compareTo);
//Like compare_exchange_strong, but will not return until the value is exchanged
void wait_compare_exchange(int xchg, int compareTo, const int spinCount);
int get() const { return value; }
operator int() const { return value; }
atomic_int() : value(0) {}
atomic_int(int v) : value(v) {}
};
//Swap a value atomically
int swap(int* ptr, int newval);
int compare_and_swap(int* ptr, int oldval, int newval);
//long long swap(long long* ptr, long long newval);
long long compare_and_swap(long long* ptr, long long oldval, long long newval);
void* swap(void** ptr, void* newval);
void* compare_and_swap(void** ptr, void* oldval, void* newval);
class _threadlocalPointer {
#ifdef _MSC_VER
long index;
#elif defined(__GNUC__)
pthread_key_t key;
#endif
public:
_threadlocalPointer();
~_threadlocalPointer();
void set(void* ptr);
void* get();
};
template<class T>
class threadlocalPointer : public _threadlocalPointer {
public:
inline operator T*() {
return (T*)get();
}
inline void operator=(T* ptr) {
set((void*)ptr);
}
inline T* operator->() {
return (T*)get();
}
};
enum ThreadPriority {
TP_High,
TP_Normal,
TP_Low
};
extern const int invalidThreadID;
void createThread(threadfunc func, void* arg);
int getThreadID();
void setThreadPriority(ThreadPriority priority);
struct Mutex {
private:
atomic_int owningThread;
unsigned lockCount;
static const unsigned spinCount;
public:
#ifdef PROFILE_LOCKS
atomic_int profileCount;
std::string name;
bool observed;
Mutex();
Mutex(const char* name);
~Mutex();
#endif
void lock();
bool try_lock();
void release();
bool hasLock();
};
struct Lock {
private:
Mutex* mutex;
public:
Lock(Mutex& mtx) : mutex(&mtx) { mtx.lock(); }
~Lock() { mutex->release(); }
};
struct ReadWriteMutex {
private:
atomic_int owningThread;
atomic_int readCount;
static const unsigned spinCount;
public:
#ifdef PROFILE_LOCKS
atomic_int profileReadCount;
atomic_int profileWriteCount;
std::string name;
bool observed;
ReadWriteMutex();
~ReadWriteMutex();
#endif
void writeLock();
void readLock();
void release();
bool hasLock();
bool hasWriteLock();
};
struct ReadLock {
private:
ReadWriteMutex* mutex;
public:
ReadLock(ReadWriteMutex& mtx) : mutex(&mtx) { mtx.readLock(); }
~ReadLock() { mutex->release(); }
};
struct WriteLock {
private:
ReadWriteMutex* mutex;
public:
WriteLock(ReadWriteMutex& mtx) : mutex(&mtx) { mtx.writeLock(); }
~WriteLock() { mutex->release(); }
};
struct Signal {
private:
atomic_int flag;
static const unsigned spinCount;
public:
Signal(int start = 0);
//Sets the signal to the specified value
void signal(int value);
//Reduces the signal's value by one
void signalDown();
//Increases the signal's value by one
void signalUp();
//Reduces the signal's value by a value
void signalDown(int value);
//Increases the signal's value by a value
void signalUp(int value);
//Returns true if the flag is at the value
bool check(int checkFor) const;
//Checks if the flag is at value, and sets it if it is
bool checkAndSignal(int checkFor, int newSignal);
//Waits until the value is the specified value
void wait(int waitFor) const;
//Waits until the value is not the specified value
void waitNot(int waitForNot) const;
//Waits until the value is the specified value, then sets it to a new value
void waitAndSignal(int waitFor, int newSignal);
};
template<class T>
struct SharedData {
mutable atomic_int count;
T data;
SharedData(int startCount = 1) : count(startCount), data() {}
void grab() const {
++count;
}
void drop() const {
if(--count == 0)
delete this;
}
T& operator*() {
return data;
}
const T& operator*() const {
return data;
}
T* operator->() {
return &data;
}
const T* operator->() const {
return &data;
}
};
#ifdef PROFILE_LOCKS
void profileMutexCycle(std::function<void(Mutex*)> cb);
void profileReadWriteMutexCycle(std::function<void(ReadWriteMutex*)> cb);
#endif
};