///////////////////////////////////////////////////////////////////// // 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; // ownerObj; // OwnerContainer ownerObj; // std::atomic msec; //threadData->state = OYSTER_THREAD_STATE_DEAD; if(wait) { if(std::this_thread::get_id() != this->workerThread.get_id()) if(this->workerThread.joinable()) { this->workerThread.join(); this->isCreated = false; this->threadData = 0; } } else { if(this->workerThread.joinable()) this->workerThread.detach(); } return OYSTER_THREAD_ERROR_SUCCESS; } //OYSTER_THREAD_ERROR Create(ThreadFunction fnc, IThreadObject* 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->owner = worker; // threadData->prio = OYSTER_THREAD_PRIORITY_3; // // workerThread = std::thread(fnc, this->threadData); // // if(detach) // this->workerThread.detach(); // // isCreated = true; // // return OYSTER_THREAD_ERROR_SUCCESS; //} //OYSTER_THREAD_ERROR Create(ThreadFunction fnc, Oyster::Callback::OysterCallback 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_3; // // workerThread = std::thread(fnc, this->threadData); // // if(detach) // this->workerThread.detach(); // // isCreated = true; // // 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_3; workerThread = std::thread(fnc, this->threadData); if(detach) this->workerThread.detach(); isCreated = true; return OYSTER_THREAD_ERROR_SUCCESS; } }; struct OysterThread::PrivateData { SmartPointer data; PrivateData(){} ~PrivateData() { if(data) if(data->threadData) memset(&data->threadData->ownerObj, 0, sizeof(OwnerContainer)); } OYSTER_THREAD_ERROR Create(ThreadFunction fnc, OwnerContainer worker, bool start, bool detach) { if(data) return OYSTER_THREAD_ERROR_ThreadAlreadyCreated; data = new RefData(); return data->Create(fnc, worker, start, detach); } OYSTER_THREAD_ERROR Terminate(bool wait) { if(!data) return OYSTER_THREAD_ERROR_FAILED; return data->Terminate(wait); } }; class ThreadHelp { public: static void CheckPriority(ThreadData* w) { 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) { CheckPriority(w); if(!DoWork(w)) break; CheckStatus(w); } if(w->ownerObj.value.obj) w->ownerObj.value.obj->ThreadExit(); w->state = OYSTER_THREAD_STATE_DEAD; delete w; } }; #pragma endregion OysterThread::OysterThread() { this->privateData = new PrivateData(); } 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::Create(Oyster::Callback::CallbackObject* worker, bool start, bool detach) { if(!this->privateData) this->privateData = new PrivateData(); Oyster::Callback::OysterCallback<> temp; temp.callbackType = Oyster::Callback::CallbackType_Object; temp.value = worker; return this->privateData->Create(ThreadHelp::ThreadingFunction, temp, start, detach); } OYSTER_THREAD_ERROR OysterThread::Create(Oyster::Callback::CallbackFunction::FNC worker, bool start, bool detach) { if(!this->privateData) this->privateData = new PrivateData(); Oyster::Callback::OysterCallback<> temp; temp.callbackType = Oyster::Callback::CallbackType_Function; temp.value = worker; return this->privateData->Create(ThreadHelp::ThreadingFunction, temp, start, detach); } */ OYSTER_THREAD_ERROR OysterThread::Start() { if(!this->privateData->data->threadData->ownerObj) return OYSTER_THREAD_ERROR_ThreadHasNoWorker; if(this->privateData->data->threadData->state == OYSTER_THREAD_STATE_DEAD) return OYSTER_THREAD_ERROR_ThreadIsDead; this->privateData->data->threadData->state = OYSTER_THREAD_STATE_NORMAL; return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::Stop(bool wait) { return this->Terminate(wait); } OYSTER_THREAD_ERROR OysterThread::Pause() { this->privateData->data->threadData->state = OYSTER_THREAD_STATE_IDLE; return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::Pause(int msec) { this->privateData->data->threadData->msec = msec; return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::Resume() { if(this->privateData->data->threadData->state == OYSTER_THREAD_STATE_DEAD) return OYSTER_THREAD_ERROR_ThreadIsDead; this->privateData->data->threadData->state = OYSTER_THREAD_STATE_NORMAL; return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::SetWorker(IThreadObject* worker) { this->privateData->data->threadData->ownerObj.value = worker; this->privateData->data->threadData->ownerObj.type = Oyster::Callback::CallbackType_Object; this->privateData->data->threadData->msec = 0; return OYSTER_THREAD_ERROR_SUCCESS;; } OYSTER_THREAD_ERROR OysterThread::SetWorker(ThreadFnc worker) { this->privateData->data->threadData->ownerObj.value = worker; this->privateData->data->threadData->ownerObj.type = Oyster::Callback::CallbackType_Function; this->privateData->data->threadData->msec = 0; return OYSTER_THREAD_ERROR_SUCCESS;; } OYSTER_THREAD_ERROR OysterThread::Terminate(bool wait) { return this->privateData->Terminate(wait); } OYSTER_THREAD_ERROR OysterThread::Wait() { if(this->privateData->data->threadData->state == OYSTER_THREAD_STATE_DEAD) return OYSTER_THREAD_ERROR_ThreadIsDead; if( this->privateData->data->workerThread.get_id() == std::this_thread::get_id()) return OYSTER_THREAD_ERROR_ThreadCannotWaintOnItselfe; //this->privateData->data->threadData->threadFunctionLock.lock(); //this->privateData->data->threadData->threadFunctionLock.unlock(); return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::Wait(int msec) { if(this->privateData->data->workerThread.get_id() == std::this_thread::get_id()) return OYSTER_THREAD_ERROR_ThreadCannotWaintOnItselfe; //if(this->privateData->data->threadData->threadFunctionLock.try_lock_for(std::chrono::milliseconds(msec))) // this->privateData->data->threadData->threadFunctionLock.unlock(); return OYSTER_THREAD_ERROR_SUCCESS; } OYSTER_THREAD_ERROR OysterThread::Swap(const OysterThread* other) { this->privateData->data->workerThread.swap(other->privateData->data->workerThread); 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; }