Danbias/Code/Misc/Thread/OysterThread_Impl.cpp

298 lines
7.9 KiB
C++
Raw Normal View History

2013-11-28 15:17:25 +01:00
/////////////////////////////////////////////////////////////////////
// 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;
2013-11-28 15:17:25 +01:00
#pragma region Declerations
struct ThreadData;
/** A typical Oyster thread function */
typedef void (*ThreadFunction)(SmartPointer<ThreadData>&);
2013-11-28 15:17:25 +01:00
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
{
2013-12-13 23:47:16 +01:00
OYSTER_THREAD_STATE state; //<! The current thread state.
OYSTER_THREAD_PRIORITY prio; //<! The thread priority
SmartPointer<std::thread> workerThread; //<! The worker thread.
2013-11-28 15:17:25 +01:00
std::thread::id callingThread; //<! The owner thread.
IThreadObject *owner; //<! The owner of the thread as IThread.
std::atomic<int> msec; //<! A timer in miliseconds.
2013-12-13 23:47:16 +01:00
bool first;
2013-11-28 15:17:25 +01:00
ThreadData() {}
2013-12-13 23:47:16 +01:00
~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();
}
}
2013-12-12 12:54:08 +01:00
ThreadData(const ThreadData&)
{};
const ThreadData& operator =(const ThreadData& o)
{};
2013-11-28 15:17:25 +01:00
};
struct OysterThread::PrivateData
{
bool isCreated;
SmartPointer<ThreadData> threadData;
2013-11-28 15:17:25 +01:00
PrivateData()
{
isCreated = false;
2013-12-13 23:47:16 +01:00
threadData = new ThreadData();
threadData->first = true;
2013-11-28 15:17:25 +01:00
threadData->owner = 0;
threadData->workerThread = 0;
threadData->callingThread;
threadData->state = OYSTER_THREAD_STATE_STOPED;
2013-12-13 23:47:16 +01:00
threadData->prio = OYSTER_THREAD_PRIORITY_3;
2013-11-28 15:17:25 +01:00
}
PrivateData(const PrivateData& o)
{
isCreated = o.isCreated;
2013-11-28 15:17:25 +01:00
threadData = o.threadData;
}
2013-12-12 12:54:08 +01:00
const PrivateData& operator=(const PrivateData& o)
{
threadData = o.threadData;
}
2013-11-28 15:17:25 +01:00
~PrivateData()
{
2013-12-17 10:25:34 +01:00
//if(threadData.Release() == 0)
//{
// if(this->threadData->workerThread->joinable())
// {
// this->threadData->workerThread->join();
// }
//}
2013-11-28 15:17:25 +01:00
}
};
#pragma endregion
static void ThreadingFunction(SmartPointer<ThreadData> &origin)
2013-11-28 15:17:25 +01:00
{
2013-12-13 23:47:16 +01:00
bool shouldContinue = true;
SmartPointer<ThreadData> w = origin;
2013-11-28 15:17:25 +01:00
theBegining:
2013-12-13 23:47:16 +01:00
while(w->state == OYSTER_THREAD_STATE_STOPED) std::this_thread::yield();
2013-11-28 15:17:25 +01:00
2013-12-13 23:47:16 +01:00
if(w->owner) w->owner->ThreadEntry();
w->first = false;
while (w->state != OYSTER_THREAD_STATE_STOPED && w->state != OYSTER_THREAD_STATE_DEAD && shouldContinue)
2013-11-28 15:17:25 +01:00
{
2013-12-13 23:47:16 +01:00
switch (w->prio)
2013-11-28 15:17:25 +01:00
{
2013-12-13 23:47:16 +01:00
case Oyster::Thread::OYSTER_THREAD_PRIORITY_2:
std::this_thread::sleep_for(std::chrono::milliseconds(1));
break;
case Oyster::Thread::OYSTER_THREAD_PRIORITY_3:
2013-12-17 14:15:20 +01:00
std::this_thread::sleep_for(std::chrono::milliseconds(10));
//std::this_thread::yield();
2013-12-13 23:47:16 +01:00
break;
2013-11-28 15:17:25 +01:00
}
2013-12-17 10:25:34 +01:00
if(w->owner)
shouldContinue = w->owner->DoWork();
2013-12-13 23:47:16 +01:00
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();
2013-11-28 15:17:25 +01:00
}
if(w->state == OYSTER_THREAD_STATE_DEAD)
{
2013-12-17 10:25:34 +01:00
if(w->workerThread->joinable())
w->workerThread->detach();
2013-12-13 23:47:16 +01:00
2013-11-28 15:17:25 +01:00
return;
}
//theEnd:
2013-12-13 23:47:16 +01:00
if(w->owner) w->owner->ThreadExit();
2013-11-28 15:17:25 +01:00
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)
{
2013-12-12 12:54:08 +01:00
delete this->privateData;
this->privateData = new PrivateData(*original.privateData);
2013-11-28 15:17:25 +01:00
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;
2013-12-17 10:25:34 +01:00
if(this->IsCreated()) return OYSTER_THREAD_ERROR_FAILED;
2013-11-28 15:17:25 +01:00
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;
}
2013-12-17 10:25:34 +01:00
this->privateData->isCreated = true;
2013-11-28 15:17:25 +01:00
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;
}
2013-12-13 23:47:16 +01:00
void OysterThread::Stop(bool wait)
2013-11-28 15:17:25 +01:00
{
//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;
}
2013-12-13 23:47:16 +01:00
void OysterThread::Terminate(bool wait)
2013-11-28 15:17:25 +01:00
{
this->privateData->threadData->state = OYSTER_THREAD_STATE_DEAD;
}
void OysterThread::Wait()
{
if(this->privateData->threadData->state == OYSTER_THREAD_STATE_DEAD)
2013-12-13 23:47:16 +01:00
{ return; }
2013-11-28 15:17:25 +01:00
2013-12-13 23:47:16 +01:00
if( this->privateData->threadData->workerThread
&&
this->privateData->threadData->workerThread->get_id() == std::this_thread::get_id())
return;
2013-11-28 15:17:25 +01:00
2013-12-13 23:47:16 +01:00
//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();
2013-11-28 15:17:25 +01:00
}
void OysterThread::Wait(int msec)
{
if(this->privateData->threadData->workerThread->get_id() == std::this_thread::get_id()) return;
2013-12-13 23:47:16 +01:00
//TODO: Sync with thread.
//std::this_thread::sleep_for(std::chrono::milliseconds(msec));
2013-11-28 15:17:25 +01:00
}
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;
}
2013-12-13 23:47:16 +01:00
void OysterThread::SetPriority(OYSTER_THREAD_PRIORITY priority)
{
this->privateData->threadData->prio = priority;
}
bool OysterThread::IsCreated() const
{
return privateData->isCreated;
}