Danbias/Code/Misc/Utilities/Thread/OysterThread_Impl.cpp

394 lines
10 KiB
C++
Raw Normal View History

2013-11-28 15:17:25 +01:00
/////////////////////////////////////////////////////////////////////
// Created by [Dennis Andersen] [2013]
/////////////////////////////////////////////////////////////////////
#include "OysterThread.h"
#include "..\Utilities.h"
2014-01-07 10:26:09 +01:00
#include "..\OysterCallback.h"
2013-11-28 15:17:25 +01:00
#include <thread>
#include <assert.h>
#include <atomic>
2013-12-19 12:32:23 +01:00
#include <future>
2013-11-28 15:17:25 +01:00
using namespace Oyster::Thread;
using namespace Utility::DynamicMemory;
2013-11-28 15:17:25 +01:00
2013-12-19 12:32:23 +01:00
#pragma region Declerations
2013-11-28 15:17:25 +01:00
enum OYSTER_THREAD_STATE
{
2013-12-19 12:32:23 +01:00
OYSTER_THREAD_STATE_IDLE,
OYSTER_THREAD_STATE_NORMAL,
2013-11-28 15:17:25 +01:00
OYSTER_THREAD_STATE_DEAD,
};
2014-01-07 10:26:09 +01:00
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);
}
};
2013-11-28 15:17:25 +01:00
struct ThreadData
{
OYSTER_THREAD_STATE state; //<! The current thread state.
OYSTER_THREAD_PRIORITY prio; //<! The thread priority
OwnerContainer ownerObj; //
int msec; //<! A timer in miliseconds.
2013-12-19 12:32:23 +01:00
};
2013-12-20 09:42:02 +01:00
2013-12-19 12:32:23 +01:00
/** A typical Oyster thread function */
typedef void (*ThreadFunction)(ThreadData* w);
struct RefData
{
bool isCreated;
bool isAlive;
2013-12-19 12:32:23 +01:00
ThreadData *threadData;
std::thread workerThread;
RefData()
{
threadData = 0;
isCreated = false;
}
~RefData()
{
2014-01-07 10:26:09 +01:00
//threadWaitFunctionLock.lock();
Terminate();
2014-01-07 10:26:09 +01:00
//threadWaitFunctionLock.unlock();
2013-12-19 12:32:23 +01:00
}
OYSTER_THREAD_ERROR Terminate()
2013-12-13 23:47:16 +01:00
{
2013-12-19 12:32:23 +01:00
if(!threadData) return OYSTER_THREAD_ERROR_SUCCESS;
2013-12-13 23:47:16 +01:00
if(std::this_thread::get_id() != this->workerThread.get_id())
{
//this->threadData->threadDataAcces.lock();
//{
this->threadData->state = OYSTER_THREAD_STATE_DEAD;
2013-12-19 12:32:23 +01:00
if(this->workerThread.joinable())
{
this->workerThread.join();
}
this->isCreated = false;
delete this->threadData;
this->threadData = 0;
//} this->threadData->threadDataAcces.unlock();
}
else
2013-12-19 12:32:23 +01:00
{
this->threadData->state = OYSTER_THREAD_STATE_DEAD;
if(this->workerThread.joinable())
{
this->workerThread.join();
}
this->isCreated = false;
delete this->threadData;
this->threadData = 0;
2013-12-13 23:47:16 +01:00
}
2013-12-19 12:32:23 +01:00
return OYSTER_THREAD_ERROR_SUCCESS;
}
2014-01-07 10:26:09 +01:00
OYSTER_THREAD_ERROR Create(ThreadFunction fnc, OwnerContainer worker, bool start, bool detach)
2013-12-19 12:32:23 +01:00
{
if(this->isCreated ) return OYSTER_THREAD_ERROR_ThreadAlreadyCreated;
2013-12-19 12:32:23 +01:00
threadData = new ThreadData();
if(start)
this->threadData->state = OYSTER_THREAD_STATE_NORMAL;
else
this->threadData->state = OYSTER_THREAD_STATE_IDLE;
2014-01-07 10:26:09 +01:00
threadData->ownerObj = worker;
2014-01-20 15:47:52 +01:00
threadData->prio = OYSTER_THREAD_PRIORITY_2;
threadData->msec = 0;
2013-12-19 12:32:23 +01:00
workerThread = std::thread(fnc, this->threadData);
isCreated = true;
return OYSTER_THREAD_ERROR_SUCCESS;
2013-12-13 23:47:16 +01:00
}
2013-11-28 15:17:25 +01:00
};
2014-01-07 10:26:09 +01:00
2013-11-28 15:17:25 +01:00
struct OysterThread::PrivateData
{
2013-12-19 12:32:23 +01:00
SmartPointer<RefData> data;
2014-01-29 10:18:01 +01:00
PrivateData()
{
data = new RefData();
}
2014-01-07 10:26:09 +01:00
~PrivateData()
{
2014-01-29 10:18:01 +01:00
data = 0;
2014-01-07 10:26:09 +01:00
}
OYSTER_THREAD_ERROR Create(ThreadFunction fnc, OwnerContainer worker, bool start, bool detach)
2013-12-19 12:32:23 +01:00
{
2014-01-29 10:18:01 +01:00
if(!data) data = new RefData();
2013-12-19 12:32:23 +01:00
return data->Create(fnc, worker, start, detach);
}
OYSTER_THREAD_ERROR Terminate()
2013-11-28 15:17:25 +01:00
{
2014-01-07 10:26:09 +01:00
if(!data)
return OYSTER_THREAD_ERROR_FAILED;
return data->Terminate();
2013-11-28 15:17:25 +01:00
}
2013-12-19 12:32:23 +01:00
};
class ThreadHelp
{
public:
static void CheckPriority(ThreadData* w)
2013-11-28 15:17:25 +01:00
{
Oyster::Thread::OYSTER_THREAD_PRIORITY temp = w->prio;
2013-12-19 12:32:23 +01:00
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;
}
2013-11-28 15:17:25 +01:00
}
2013-12-19 12:32:23 +01:00
static bool DoWork(ThreadData* w)
2013-12-12 12:54:08 +01:00
{
2014-01-07 10:26:09 +01:00
switch (w->ownerObj.type)
2013-12-20 09:42:02 +01:00
{
2014-01-07 10:26:09 +01:00
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;
2013-12-20 09:42:02 +01:00
}
2014-01-07 10:26:09 +01:00
2013-12-19 12:32:23 +01:00
return true;
2013-12-12 12:54:08 +01:00
}
2013-12-19 12:32:23 +01:00
static void CheckStatus(ThreadData* w)
2013-11-28 15:17:25 +01:00
{
2013-12-19 12:32:23 +01:00
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();
2013-11-28 15:17:25 +01:00
}
2013-12-19 12:32:23 +01:00
static void ThreadingFunction(ThreadData* w)
{
CheckStatus(w);
2013-11-28 15:17:25 +01:00
2014-01-07 10:26:09 +01:00
if(w->ownerObj.value.obj) w->ownerObj.value.obj->ThreadEntry();
2013-11-28 15:17:25 +01:00
2013-12-19 12:32:23 +01:00
while (w->state == OYSTER_THREAD_STATE_NORMAL)
{
//while (!w->threadDataAcces.try_lock());
CheckPriority(w);
if(!DoWork(w)) break;
CheckStatus(w);
//w->threadDataAcces.unlock();
2013-12-19 12:32:23 +01:00
}
2013-11-28 15:17:25 +01:00
2014-01-07 10:26:09 +01:00
if(w->ownerObj.value.obj) w->ownerObj.value.obj->ThreadExit();
2013-11-28 15:17:25 +01:00
2013-12-19 12:32:23 +01:00
w->state = OYSTER_THREAD_STATE_DEAD;
2013-11-28 15:17:25 +01:00
}
2013-12-19 12:32:23 +01:00
};
2013-12-13 23:47:16 +01:00
2013-12-19 12:32:23 +01:00
#pragma endregion
2013-11-28 15:17:25 +01:00
OysterThread::OysterThread()
2014-01-29 10:18:01 +01:00
:privateData(0)
{ }
2013-11-28 15:17:25 +01:00
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;
2013-12-19 12:32:23 +01:00
this->privateData = new PrivateData();
this->privateData->data = original.privateData->data;
2013-11-28 15:17:25 +01:00
return *this;
}
OysterThread::~OysterThread()
{
delete this->privateData;
this->privateData = 0;
}
2013-12-19 12:32:23 +01:00
OYSTER_THREAD_ERROR OysterThread::Create(IThreadObject* worker, bool start, bool detach)
2014-01-07 10:26:09 +01:00
{
2014-01-29 10:18:01 +01:00
if(!this->privateData) this->privateData = new PrivateData();
2014-01-07 10:26:09 +01:00
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)
{
2014-01-29 10:18:01 +01:00
if(!this->privateData) this->privateData = new PrivateData();
2014-01-07 10:26:09 +01:00
OwnerContainer c;
c.type = Oyster::Callback::CallbackType_Function;
c.value = worker;
return this->privateData->Create(ThreadHelp::ThreadingFunction, c, start, detach);
}
2013-12-19 12:32:23 +01:00
OYSTER_THREAD_ERROR OysterThread::Start()
{
OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS;
//this->privateData->data->threadData->threadDataAcces.lock();{
2013-11-28 15:17:25 +01:00
if(!this->privateData->data->threadData->ownerObj)
val = OYSTER_THREAD_ERROR_ThreadHasNoWorker;
2013-11-28 15:17:25 +01:00
if(this->privateData->data->threadData->state == OYSTER_THREAD_STATE_DEAD)
val = OYSTER_THREAD_ERROR_ThreadIsDead;
2013-12-17 10:25:34 +01:00
this->privateData->data->threadData->state = OYSTER_THREAD_STATE_NORMAL;
//} this->privateData->data->threadData->threadDataAcces.unlock();
return val;
2013-11-28 15:17:25 +01:00
}
OYSTER_THREAD_ERROR OysterThread::Stop()
2013-11-28 15:17:25 +01:00
{
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;
2013-11-28 15:17:25 +01:00
}
2014-01-28 09:00:02 +01:00
OYSTER_THREAD_ERROR OysterThread::Stop(int msec)
2013-11-28 15:17:25 +01:00
{
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;
2013-11-28 15:17:25 +01:00
}
2013-12-19 12:32:23 +01:00
OYSTER_THREAD_ERROR OysterThread::Resume()
2013-11-28 15:17:25 +01:00
{
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;
2013-11-28 15:17:25 +01:00
this->privateData->data->threadData->state = OYSTER_THREAD_STATE_NORMAL;
//} this->privateData->data->threadData->threadDataAcces.unlock();
2013-12-19 12:32:23 +01:00
return val;
2013-11-28 15:17:25 +01:00
}
2014-01-07 10:26:09 +01:00
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;
2014-01-07 10:26:09 +01:00
this->privateData->data->threadData->msec = 0;
//} this->privateData->data->threadData->threadDataAcces.unlock();
2014-01-07 10:26:09 +01:00
return val;;
2014-01-07 10:26:09 +01:00
}
OYSTER_THREAD_ERROR OysterThread::SetWorker(ThreadFnc worker)
2013-11-28 15:17:25 +01:00
{
OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS;
//this->privateData->data->threadData->threadDataAcces.lock();{
2013-11-28 15:17:25 +01:00
this->privateData->data->threadData->ownerObj.value = worker;
this->privateData->data->threadData->ownerObj.type = Oyster::Callback::CallbackType_Function;
2013-12-19 12:32:23 +01:00
this->privateData->data->threadData->msec = 0;
//} this->privateData->data->threadData->threadDataAcces.unlock();
return val;;
2013-11-28 15:17:25 +01:00
}
OYSTER_THREAD_ERROR OysterThread::Terminate()
2013-11-28 15:17:25 +01:00
{
2014-01-30 00:19:00 +01:00
if(this->privateData)
return this->privateData->Terminate();
2014-01-30 00:19:00 +01:00
return OYSTER_THREAD_ERROR_SUCCESS;
2013-11-28 15:17:25 +01:00
}
2013-12-19 12:32:23 +01:00
OYSTER_THREAD_ERROR OysterThread::Wait()
2013-11-28 15:17:25 +01:00
{
OYSTER_THREAD_ERROR val = OYSTER_THREAD_ERROR_SUCCESS;
2013-11-28 15:17:25 +01:00
//this->privateData->data->threadData->threadDataAcces.lock();{
2013-12-13 23:47:16 +01:00
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;
2013-11-28 15:17:25 +01:00
}
2013-12-19 12:32:23 +01:00
OYSTER_THREAD_ERROR OysterThread::Wait(int msec)
2013-11-28 15:17:25 +01:00
{
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;
2013-11-28 15:17:25 +01:00
}
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();
2013-11-28 15:17:25 +01:00
return OYSTER_THREAD_ERROR_SUCCESS;
}
2013-12-19 12:32:23 +01:00
void OysterThread::SetPriority(OYSTER_THREAD_PRIORITY priority)
{
this->privateData->data->threadData->prio = priority;
}
2013-11-28 15:17:25 +01:00
bool OysterThread::IsActive()
{
2013-12-19 12:32:23 +01:00
if (this->privateData->data->threadData->state == OYSTER_THREAD_STATE_NORMAL)
2013-11-28 15:17:25 +01:00
return true;
return false;
}
bool OysterThread::IsCreated() const
{
2013-12-19 13:35:56 +01:00
if(!privateData->data) return false;
2013-12-19 12:32:23 +01:00
return privateData->data->isCreated;
}