diff --git a/Code/Misc/Thread/IThreadObject.h b/Code/Misc/Thread/IThreadObject.h new file mode 100644 index 00000000..b21c942e --- /dev/null +++ b/Code/Misc/Thread/IThreadObject.h @@ -0,0 +1,37 @@ +///////////////////////////////////////////////////////////////////// +// Created by [Dennis Andersen] [2013] +///////////////////////////////////////////////////////////////////// + +#ifndef MISC_I_THREAD_OBJECT_H +#define MISC_I_THREAD_OBJECT_H + + + +namespace Oyster +{ + namespace Thread + { + /** + * Inherit this class to get threading compatibility. + */ + class IThreadObject + { + public: + /** + * Override this to get notified when the thread is started. + */ + virtual void ThreadEntry() { } + /** + * Override this to get notified when the thread is about to exit. + */ + virtual void ThreadExit() { } + /** + * This function is required to get threading working. + */ + virtual bool DoWork ( ) = 0; + }; + } +} + +#endif // !MISC_I_THREAD_OBJECT_H + diff --git a/Code/Misc/Thread/OysterMutex.cpp b/Code/Misc/Thread/OysterMutex.cpp new file mode 100644 index 00000000..089323ce --- /dev/null +++ b/Code/Misc/Thread/OysterMutex.cpp @@ -0,0 +1,66 @@ +///////////////////////////////////////////////////////////////////// +// Created by [Dennis Andersen] [2013] +///////////////////////////////////////////////////////////////////// + +#include "OysterMutex.h" + +#include +#include +#include + + + +OysterMutex::OysterMutex() +{} + +OysterMutex::OysterMutex(bool initialOwnership) +{ + if(initialOwnership) + { + this->mutex.lock(); + this->id = std::this_thread::get_id(); + } +} +OysterMutex::~OysterMutex() +{ +} +void OysterMutex::LockMutex() +{ + if(std::this_thread::get_id() == this->id) return; + + this->mutex.lock(); + + this->id = std::this_thread::get_id(); +} +void OysterMutex::LockMutex(unsigned int msec) +{ + if(std::this_thread::get_id() == this->id) return; + + auto start = std::chrono::high_resolution_clock::now(); + auto end = start + std::chrono::milliseconds(msec); + + do + { + if(this->mutex.try_lock()) + { + this->mutex.lock(); + this->id = std::this_thread::get_id(); + return; + } + } while (std::chrono::high_resolution_clock::now() < end); + + this->mutex.lock(); +} +void OysterMutex::UnlockMutex() +{ + //Let the owner unlock + if(std::this_thread::get_id() != this->id) return; + + this->mutex.unlock(); + this->id = std::thread::id(); + +} +bool OysterMutex::IsTaken() +{ + return !this->mutex.try_lock(); +} \ No newline at end of file diff --git a/Code/Misc/Thread/OysterMutex.h b/Code/Misc/Thread/OysterMutex.h index d9f29d95..18282499 100644 --- a/Code/Misc/Thread/OysterMutex.h +++ b/Code/Misc/Thread/OysterMutex.h @@ -9,29 +9,23 @@ #include #include -namespace Oyster +class OysterMutex { - namespace Thread - { - class OysterMutex - { - public: - OysterMutex(); - OysterMutex(bool initialOwnership); - virtual~OysterMutex(); - void LockMutex(); - void LockMutex(unsigned int timeSpan); - void UnlockMutex(); - /** Returns true if mutex is taken */ - bool IsTaken(); +public: + OysterMutex(); + OysterMutex(bool initialOwnership); + virtual~OysterMutex(); + void LockMutex(); + void LockMutex(unsigned int timeSpan); + void UnlockMutex(); + /** Returns true if mutex is taken */ + bool IsTaken(); - private: - std::mutex mutex; - std::thread::id id; +private: + std::mutex mutex; + std::thread::id id; - OysterMutex(const OysterMutex&); - }; - } -} + OysterMutex(const OysterMutex&); +}; #endif // !MISC_OYSTER_MUTEX_H diff --git a/Code/Misc/Thread/OysterThread.h b/Code/Misc/Thread/OysterThread.h new file mode 100644 index 00000000..05a9f8ad --- /dev/null +++ b/Code/Misc/Thread/OysterThread.h @@ -0,0 +1,47 @@ +///////////////////////////////////////////////////////////////////// +// Created by [Dennis Andersen] [2013] +///////////////////////////////////////////////////////////////////// + +#ifndef MISC_OYSTER_THREAD_H +#define MISC_OYSTER_THREAD_H + +#include "IThreadObject.h" +namespace Oyster +{ + namespace Thread + { + enum OYSTER_THREAD_ERROR + { + OYSTER_THREAD_ERROR_FAILED, + OYSTER_THREAD_ERROR_SUCCESS, + }; + + class OysterThread + { + private: + struct PrivateData; + PrivateData *privateData; + + public: + OysterThread(); + OysterThread(const OysterThread& original); + const OysterThread& operator=(const OysterThread& original); + virtual~OysterThread(); + + OYSTER_THREAD_ERROR Create(IThreadObject* worker, bool start); + OYSTER_THREAD_ERROR Start(); + void Stop(); + void Pause(); + void Pause(int mSec); + void Resume(); + OYSTER_THREAD_ERROR Reset(IThreadObject* worker = 0); + void Terminate(); + void Wait(); + void Wait(int mSec); + OYSTER_THREAD_ERROR Swap(const OysterThread* other); + bool IsActive(); + }; + } +} + +#endif // !MISC_OYSTER_THREAD_H diff --git a/Code/Misc/Thread/OysterThread_Impl.cpp b/Code/Misc/Thread/OysterThread_Impl.cpp new file mode 100644 index 00000000..46b889fe --- /dev/null +++ b/Code/Misc/Thread/OysterThread_Impl.cpp @@ -0,0 +1,281 @@ +///////////////////////////////////////////////////////////////////// +// Created by [Dennis Andersen] [2013] +///////////////////////////////////////////////////////////////////// + +#include "OysterThread.h" +#include "OysterMutex.h" +#include "..\Utilities.h" +#include +#include +#include + +using namespace Oyster::Thread; +using namespace Utility::DynamicMemory::SmartPointer; + + +#pragma region Declerations + + struct ThreadData; + /** A typical Oyster thread function */ + typedef void (*ThreadFunction)(StdSmartPointer&); + + enum OYSTER_THREAD_STATE + { + OYSTER_THREAD_STATE_RESET, + OYSTER_THREAD_STATE_RUNNING, + OYSTER_THREAD_STATE_PAUSED, + OYSTER_THREAD_STATE_STOPED, + OYSTER_THREAD_STATE_DEAD, + }; + + + struct ThreadData + { + std::atomic state; // workerThread; // msec; // threadData; + + PrivateData() + :threadData(new ThreadData()) + { + threadData->owner = 0; + threadData->workerThread = 0; + threadData->callingThread; + threadData->state = OYSTER_THREAD_STATE_STOPED; + } + PrivateData(const PrivateData& o) + { + threadData = o.threadData; + } + ~PrivateData() + { + //@todo TODO: Make detatch avalible. + this->threadData->workerThread->detach(); + + this->threadData->owner = 0; + + this->threadData->state = OYSTER_THREAD_STATE_DEAD; + } + + }; + +#pragma endregion + + +int tempId = 0; +std::vector IDS; +static void ThreadingFunction(StdSmartPointer &origin) +{ + + bool shouldContinue; + StdSmartPointer w = origin; + +theBegining: + + while(w->state == OYSTER_THREAD_STATE_STOPED) + { + std::this_thread::yield(); + } + +// w->mutexLock.LockMutex(); + if(w->owner) + { + w->owner->ThreadEntry(); + } +// w->mutexLock.UnlockMutex(); + + while (w->state != OYSTER_THREAD_STATE_STOPED && w->state != OYSTER_THREAD_STATE_DEAD) + { +// w->mutexLock.LockMutex(); + { + if(w->owner) + { + shouldContinue = w->owner->DoWork(); + } + } +// w->mutexLock.UnlockMutex(); + + if(!shouldContinue) + { + goto theEnd; + } + if(w->state == OYSTER_THREAD_STATE_DEAD) + { + goto theEnd; + } + else if(w->state == OYSTER_THREAD_STATE_RESET) + { + goto theBegining; + } + else if(w->msec > 0) + { + std::this_thread::sleep_for(std::chrono::milliseconds(w->msec)); + } + + while (w->state == OYSTER_THREAD_STATE_PAUSED) + { + std::this_thread::yield(); + } + } + + if(w->state == OYSTER_THREAD_STATE_DEAD) + { + w->workerThread->detach(); + return; + } + +theEnd: + +// w->mutexLock.LockMutex(); + if(w->owner) + { + w->owner->ThreadExit(); + } +// w->mutexLock.UnlockMutex(); + + w->state = OYSTER_THREAD_STATE_DEAD; +} + +OysterThread::OysterThread() +{ + this->privateData = new PrivateData(); +} +OysterThread::OysterThread(const OysterThread& original) +{ + this->privateData = new PrivateData(*original.privateData); +} +const OysterThread& OysterThread::operator=(const OysterThread& original) +{ + return *this; +} +OysterThread::~OysterThread() +{ + delete this->privateData; + this->privateData = 0; +} + +OYSTER_THREAD_ERROR OysterThread::Create(IThreadObject* worker, bool start) +{ + if(!this->privateData) return OYSTER_THREAD_ERROR_FAILED; + if(this->privateData->threadData->workerThread) return OYSTER_THREAD_ERROR_FAILED; + + this->privateData->threadData->owner = worker; + + ThreadFunction fnc = ThreadingFunction; + + //Maby move this thread creation to a seperate Start() function because std::thread fires the thread when it is created. :( + this->privateData->threadData->workerThread = new std::thread(fnc, this->privateData->threadData); + + if(!this->privateData->threadData->workerThread) + return OYSTER_THREAD_ERROR_FAILED; + + if(start) + { + this->privateData->threadData->state = OYSTER_THREAD_STATE_RUNNING; + } + return OYSTER_THREAD_ERROR_SUCCESS; +} +OYSTER_THREAD_ERROR OysterThread::Start() +{ + if(!this->privateData->threadData->owner) + return OYSTER_THREAD_ERROR_FAILED; + if(!this->privateData->threadData->workerThread) + return OYSTER_THREAD_ERROR_FAILED; + if(this->privateData->threadData->state == OYSTER_THREAD_STATE_DEAD) + return OYSTER_THREAD_ERROR_FAILED; + + this->privateData->threadData->state = OYSTER_THREAD_STATE_RUNNING; + return OYSTER_THREAD_ERROR_SUCCESS; +} +void OysterThread::Stop() +{ + //this->privateData->threadData->mutexLock.LockMutex(); + this->privateData->threadData->state = OYSTER_THREAD_STATE_STOPED; + //this->privateData->threadData->mutexLock.UnlockMutex(); +} +void OysterThread::Pause() +{ + //this->privateData->threadData->mutexLock.LockMutex(); + this->privateData->threadData->state = OYSTER_THREAD_STATE_PAUSED; + //this->privateData->threadData->mutexLock.UnlockMutex(); +} +void OysterThread::Pause(int msec) +{ + + if(std::this_thread::get_id() == this->privateData->threadData->workerThread->get_id()) + { + this->privateData->threadData->msec = msec; + } + else + { + //this->privateData->threadData->mutexLock.LockMutex(); + this->privateData->threadData->state = OYSTER_THREAD_STATE_PAUSED; + this->privateData->threadData->msec = msec; + //this->privateData->threadData->mutexLock.UnlockMutex(); + } +} +void OysterThread::Resume() +{ +// this->privateData->threadData->mutexLock.LockMutex(); + this->privateData->threadData->state = OYSTER_THREAD_STATE_RUNNING; +// this->privateData->threadData->mutexLock.UnlockMutex(); +} +OYSTER_THREAD_ERROR OysterThread::Reset(IThreadObject* worker) +{ +// this->privateData->threadData->mutexLock.LockMutex(); + if(worker) + { + this->privateData->threadData->owner = worker; + } + this->privateData->threadData->callingThread = std::this_thread::get_id(); + this->privateData->threadData->msec = 0; +// this->privateData->threadData->mutexLock.UnlockMutex(); + + return OYSTER_THREAD_ERROR_SUCCESS; +} +void OysterThread::Terminate() +{ + this->privateData->threadData->state = OYSTER_THREAD_STATE_DEAD; +} +void OysterThread::Wait() +{ + if(this->privateData->threadData->state == OYSTER_THREAD_STATE_DEAD) + { + return; + } + + if(this->privateData->threadData->workerThread->get_id() == std::this_thread::get_id()) return; + + this->privateData->threadData->workerThread->join(); +} +void OysterThread::Wait(int msec) +{ + if(this->privateData->threadData->workerThread->get_id() == std::this_thread::get_id()) return; + + std::this_thread::sleep_for(std::chrono::milliseconds(msec)); +} +OYSTER_THREAD_ERROR OysterThread::Swap(const OysterThread* other) +{ + this->privateData->threadData->workerThread->swap(*other->privateData->threadData->workerThread); + return OYSTER_THREAD_ERROR_SUCCESS; +} +bool OysterThread::IsActive() +{ + if (this->privateData->threadData->state == OYSTER_THREAD_STATE_RUNNING) + return true; + + return false; +} +