///////////////////////////////////////////////////////////////////// // Created by [Dennis Andersen] [2013] ///////////////////////////////////////////////////////////////////// #include "OysterThread.h" #include "..\Utilities.h" #include "..\OysterCallback.h" #include #include #include #include using namespace Oyster::Thread; using namespace Utility::DynamicMemory; #pragma region Declerations enum OYSTER_THREAD_STATE { OYSTER_THREAD_STATE_IDLE, OYSTER_THREAD_STATE_NORMAL, OYSTER_THREAD_STATE_DEAD, }; struct OwnerContainer { Oyster::Callback::CallbackType type; union OwnerValue { IThreadObject* obj; ThreadFnc fnc; OwnerValue() { memset(this, 0, sizeof(OwnerValue)); } OwnerValue(IThreadObject* v) { obj = v; } OwnerValue(ThreadFnc v) { fnc = v; } } value; operator bool() { return (value.fnc ||value.obj); } }; struct ThreadData { OYSTER_THREAD_STATE state; //workerThread.get_id()) { //this->threadData->threadDataAcces.lock(); //{ this->threadData->state = OYSTER_THREAD_STATE_DEAD; if(this->workerThread.joinable()) { this->workerThread.join(); } this->isCreated = false; delete this->threadData; this->threadData = 0; //} this->threadData->threadDataAcces.unlock(); } else { this->threadData->state = OYSTER_THREAD_STATE_DEAD; if(this->workerThread.joinable()) { this->workerThread.join(); } this->isCreated = false; delete this->threadData; this->threadData = 0; } return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR Create(ThreadFunction fnc, OwnerContainer worker, bool start, bool detach) { if(this->isCreated ) return OYSTER_THREAD_ERROR_ThreadAlreadyCreated; threadData = new ThreadData(); if(start) this->threadData->state = OYSTER_THREAD_STATE_NORMAL; else this->threadData->state = OYSTER_THREAD_STATE_IDLE; threadData->ownerObj = worker; threadData->prio = OYSTER_THREAD_PRIORITY_2; threadData->msec = 0; workerThread = std::thread(fnc, this->threadData); isCreated = true; return OYSTER_THREAD_ERROR_SUCCESS; } }; struct OysterThread::PrivateData { SmartPointer data; PrivateData() { data = new RefData(); } ~PrivateData() { data = 0; } OYSTER_THREAD_ERROR Create(ThreadFunction fnc, OwnerContainer worker, bool start, bool detach) { if(!data) data = new RefData(); return data->Create(fnc, worker, start, detach); } OYSTER_THREAD_ERROR Terminate() { if(!data) return OYSTER_THREAD_ERROR_FAILED; return data->Terminate(); } }; class ThreadHelp { public: static void CheckPriority(ThreadData* w) { Oyster::Thread::OYSTER_THREAD_PRIORITY temp = w->prio; switch (w->prio) { case Oyster::Thread::OYSTER_THREAD_PRIORITY_1: std::this_thread::sleep_for(std::chrono::milliseconds(1)); break; case Oyster::Thread::OYSTER_THREAD_PRIORITY_2: std::this_thread::sleep_for(std::chrono::milliseconds(50)); break; case Oyster::Thread::OYSTER_THREAD_PRIORITY_3: std::this_thread::sleep_for(std::chrono::milliseconds(100)); break; } } static bool DoWork(ThreadData* w) { switch (w->ownerObj.type) { case Oyster::Callback::CallbackType_Function: if(w->ownerObj.value.fnc) return w->ownerObj.value.fnc(); break; case Oyster::Callback::CallbackType_Object: if(w->ownerObj.value.obj) return w->ownerObj.value.obj->DoWork(); break; } return true; } static void CheckStatus(ThreadData* w) { if(w->msec > 0) std::this_thread::sleep_for(std::chrono::milliseconds(w->msec)); while (w->state == OYSTER_THREAD_STATE_IDLE) std::this_thread::yield(); } static void ThreadingFunction(ThreadData* w) { CheckStatus(w); if(w->ownerObj.value.obj) w->ownerObj.value.obj->ThreadEntry(); while (w->state == OYSTER_THREAD_STATE_NORMAL) { //while (!w->threadDataAcces.try_lock()); CheckPriority(w); if(!DoWork(w)) break; CheckStatus(w); //w->threadDataAcces.unlock(); } if(w->ownerObj.value.obj) w->ownerObj.value.obj->ThreadExit(); w->state = OYSTER_THREAD_STATE_DEAD; } }; #pragma endregion OysterThread::OysterThread() :privateData(0) { } OysterThread::OysterThread(const OysterThread& original) { this->privateData = new PrivateData(*original.privateData); } const OysterThread& OysterThread::operator=(const OysterThread& original) { delete this->privateData; this->privateData = new PrivateData(); this->privateData->data = original.privateData->data; return *this; } OysterThread::~OysterThread() { delete this->privateData; this->privateData = 0; } OYSTER_THREAD_ERROR OysterThread::Create(IThreadObject* worker, bool start, bool detach) { if(!this->privateData) this->privateData = new PrivateData(); OwnerContainer c; c.type = Oyster::Callback::CallbackType_Object; c.value = worker; return this->privateData->Create(ThreadHelp::ThreadingFunction, c, start, detach); } OYSTER_THREAD_ERROR OysterThread::Create(ThreadFnc worker, bool start, bool detach) { if(!this->privateData) this->privateData = new PrivateData(); OwnerContainer c; c.type = Oyster::Callback::CallbackType_Function; c.value = worker; return this->privateData->Create(ThreadHelp::ThreadingFunction, c, start, detach); } OYSTER_THREAD_ERROR OysterThread::Start() { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock();{ if(!this->privateData->data->threadData->ownerObj) val = OYSTER_THREAD_ERROR_ThreadHasNoWorker; if(this->privateData->data->threadData->state == OYSTER_THREAD_STATE_DEAD) val = OYSTER_THREAD_ERROR_ThreadIsDead; this->privateData->data->threadData->state = OYSTER_THREAD_STATE_NORMAL; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val; } OYSTER_THREAD_ERROR OysterThread::Stop() { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock(); { this->privateData->data->threadData->state = OYSTER_THREAD_STATE_IDLE; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val; } OYSTER_THREAD_ERROR OysterThread::Stop(int msec) { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock(); { this->privateData->data->threadData->msec = msec; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val; } OYSTER_THREAD_ERROR OysterThread::Resume() { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock(); { if(this->privateData->data->threadData->state == OYSTER_THREAD_STATE_DEAD) val = OYSTER_THREAD_ERROR_ThreadIsDead; this->privateData->data->threadData->state = OYSTER_THREAD_STATE_NORMAL; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val; } OYSTER_THREAD_ERROR OysterThread::SetWorker(IThreadObject* worker) { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock();{ this->privateData->data->threadData->ownerObj.value = worker; this->privateData->data->threadData->ownerObj.type = Oyster::Callback::CallbackType_Object; this->privateData->data->threadData->msec = 0; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val;; } OYSTER_THREAD_ERROR OysterThread::SetWorker(ThreadFnc worker) { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock();{ this->privateData->data->threadData->ownerObj.value = worker; this->privateData->data->threadData->ownerObj.type = Oyster::Callback::CallbackType_Function; this->privateData->data->threadData->msec = 0; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val;; } OYSTER_THREAD_ERROR OysterThread::Terminate() { if(this->privateData) return this->privateData->Terminate(); return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::Wait() { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock();{ if(this->privateData->data->threadData->state == OYSTER_THREAD_STATE_DEAD) val = OYSTER_THREAD_ERROR_ThreadIsDead; if( this->privateData->data->workerThread.get_id() == std::this_thread::get_id()) val = OYSTER_THREAD_ERROR_ThreadCannotWaintOnItselfe; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val; } OYSTER_THREAD_ERROR OysterThread::Wait(int msec) { OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS; //this->privateData->data->threadData->threadDataAcces.lock();{ if(this->privateData->data->workerThread.get_id() == std::this_thread::get_id()) val = OYSTER_THREAD_ERROR_ThreadCannotWaintOnItselfe; //} this->privateData->data->threadData->threadDataAcces.unlock(); return val; } OYSTER_THREAD_ERROR OysterThread::Swap(const OysterThread* other) { //this->privateData->data->threadData->threadDataAcces.lock();{ this->privateData->data->workerThread.swap(other->privateData->data->workerThread); //} this->privateData->data->threadData->threadDataAcces.unlock(); return OYSTER_THREAD_ERROR_SUCCESS; } void OysterThread::SetPriority(OYSTER_THREAD_PRIORITY priority) { this->privateData->data->threadData->prio = priority; } bool OysterThread::IsActive() { if (this->privateData->data->threadData->state == OYSTER_THREAD_STATE_NORMAL) return true; return false; } bool OysterThread::IsCreated() const { if(!privateData->data) return false; return privateData->data->isCreated; }