Danbias/Code/Misc/Thread/OysterThread_Impl.cpp

298 lines
7.9 KiB
C++

/////////////////////////////////////////////////////////////////////
// Created by [Dennis Andersen] [2013]
/////////////////////////////////////////////////////////////////////
#include "OysterThread.h"
#include "OysterMutex.h"
#include "..\Utilities.h"
#include <thread>
#include <assert.h>
#include <atomic>
using namespace Oyster::Thread;
using namespace Utility::DynamicMemory;
#pragma region Declerations
struct ThreadData;
/** A typical Oyster thread function */
typedef void (*ThreadFunction)(SmartPointer<ThreadData>&);
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
{
OYSTER_THREAD_STATE state; //<! The current thread state.
OYSTER_THREAD_PRIORITY prio; //<! The thread priority
SmartPointer<std::thread> workerThread; //<! The worker thread.
std::thread::id callingThread; //<! The owner thread.
IThreadObject *owner; //<! The owner of the thread as IThread.
std::atomic<int> msec; //<! A timer in miliseconds.
bool first;
ThreadData() {}
~ThreadData()
{
this->owner = 0;
this->state = OYSTER_THREAD_STATE_DEAD;
if(this->workerThread)
{
//@todo TODO: Make detatch avalible.
if(this->workerThread->joinable())
this->workerThread->detach();
}
}
ThreadData(const ThreadData&)
{};
const ThreadData& operator =(const ThreadData& o)
{};
};
struct OysterThread::PrivateData
{
bool isCreated;
SmartPointer<ThreadData> threadData;
PrivateData()
{
isCreated = false;
threadData = new ThreadData();
threadData->first = true;
threadData->owner = 0;
threadData->workerThread = 0;
threadData->callingThread;
threadData->state = OYSTER_THREAD_STATE_STOPED;
threadData->prio = OYSTER_THREAD_PRIORITY_3;
}
PrivateData(const PrivateData& o)
{
isCreated = o.isCreated;
threadData = o.threadData;
}
const PrivateData& operator=(const PrivateData& o)
{
threadData = o.threadData;
}
~PrivateData()
{
//if(threadData.Release() == 0)
//{
// if(this->threadData->workerThread->joinable())
// {
// this->threadData->workerThread->join();
// }
//}
}
};
#pragma endregion
static void ThreadingFunction(SmartPointer<ThreadData> &origin)
{
bool shouldContinue = true;
SmartPointer<ThreadData> w = origin;
theBegining:
while(w->state == OYSTER_THREAD_STATE_STOPED) std::this_thread::yield();
if(w->owner) w->owner->ThreadEntry();
w->first = false;
while (w->state != OYSTER_THREAD_STATE_STOPED && w->state != OYSTER_THREAD_STATE_DEAD && shouldContinue)
{
switch (w->prio)
{
case Oyster::Thread::OYSTER_THREAD_PRIORITY_2:
std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
case Oyster::Thread::OYSTER_THREAD_PRIORITY_3:
std::this_thread::sleep_for(std::chrono::milliseconds(10));
//std::this_thread::yield();
break;
}
if(w->owner)
shouldContinue = w->owner->DoWork();
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)
{
if(w->workerThread->joinable())
w->workerThread->detach();
return;
}
//theEnd:
if(w->owner) w->owner->ThreadExit();
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)
{
delete this->privateData;
this->privateData = new PrivateData(*original.privateData);
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->IsCreated()) 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;
}
this->privateData->isCreated = true;
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(bool wait)
{
//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->state = OYSTER_THREAD_STATE_PAUSED;
this->privateData->threadData->msec = msec;
}
}
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(bool wait)
{
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
&&
this->privateData->threadData->workerThread->get_id() == std::this_thread::get_id())
return;
//if(this->privateData->threadData->state == OYSTER_THREAD_STATE_STOPED)
if(this->privateData->threadData->first)
{ return; }
if(this->privateData->threadData->workerThread)
if(this->privateData->threadData->workerThread->joinable())
this->privateData->threadData->workerThread->join();
}
void OysterThread::Wait(int msec)
{
if(this->privateData->threadData->workerThread->get_id() == std::this_thread::get_id()) return;
//TODO: Sync with thread.
//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;
}
void OysterThread::SetPriority(OYSTER_THREAD_PRIORITY priority)
{
this->privateData->threadData->prio = priority;
}
bool OysterThread::IsCreated() const
{
return privateData->isCreated;
}