27.02.2021: worker initial commit.
This commit is contained in:
commit
01be3f95e2
5 changed files with 605 additions and 0 deletions
17
CMakeLists.txt
Normal file
17
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
cmake_minimum_required(VERSION 3.18)
|
||||
project(worker)
|
||||
|
||||
set(SOURCES
|
||||
worker.cpp
|
||||
scheduler.cpp
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
worker.h
|
||||
scheduler.h
|
||||
)
|
||||
|
||||
add_library(worker SHARED ${SOURCES} ${HEADERS})
|
||||
target_include_directories(worker PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
134
scheduler.cpp
Normal file
134
scheduler.cpp
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include "scheduler.h"
|
||||
|
||||
Scheduler::Scheduler(CreateFunc func, unsigned uMaxWorkers)
|
||||
{
|
||||
m_Create = func;
|
||||
m_uMaxWorkers = uMaxWorkers;
|
||||
}
|
||||
|
||||
Scheduler::~Scheduler()
|
||||
{
|
||||
for (auto& worker : m_Workers)
|
||||
WorkerDestroy(worker.m_pWorker);
|
||||
}
|
||||
|
||||
void Scheduler::DoControl()
|
||||
{
|
||||
if(GetState() == workstate::INIT)
|
||||
Continue(0);
|
||||
else Wait(WaitObject(SCHEDULER_DELAY));
|
||||
}
|
||||
|
||||
void Scheduler::DoWork()
|
||||
{
|
||||
for (auto it = m_Workers.begin(); it != m_Workers.end(); ++it)
|
||||
{
|
||||
Worker* wrk = it->m_pWorker;
|
||||
printf("wrk %p state %d timer %d\n", wrk,
|
||||
wrk->GetState(), it->m_iTimer);
|
||||
|
||||
try {
|
||||
if (wrk->GetState() == workstate::INIT)
|
||||
wrk->SetState(workstate::INIT, true);
|
||||
|
||||
if (wrk->IsRunning())
|
||||
{
|
||||
if (!it->m_iTimer)
|
||||
wrk->DoControl();
|
||||
}
|
||||
else continue;
|
||||
|
||||
if (wrk->GetState() == workstate::WAIT)
|
||||
{
|
||||
WaitObject& obj = wrk->GetWait();
|
||||
if (!it->m_iTimer)
|
||||
{
|
||||
switch(obj.m_Type)
|
||||
{
|
||||
case WaitObject::NoWait:
|
||||
wrk->SetState(workstate::RUNNING, true);
|
||||
break;
|
||||
case WaitObject::WaitInterval:
|
||||
it->m_iTimer = (int)obj.m_lInterval;
|
||||
break;
|
||||
case WaitObject::WaitFunction:
|
||||
printf("WaitFunction\n");
|
||||
if (obj.m_Func(obj.m_pData))
|
||||
{
|
||||
printf("OK WaitFunction\n");
|
||||
wrk->SetState(workstate::RUNNING, true);
|
||||
it->m_iTimer = 0;
|
||||
}
|
||||
else it->m_iTimer = (int)obj.m_lInterval;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
it->m_iTimer -= SCHEDULER_DELAY;
|
||||
if (it->m_iTimer <= 0)
|
||||
{
|
||||
if (obj.m_Type != WaitObject::WaitFunction)
|
||||
wrk->SetState(workstate::RUNNING, true);
|
||||
it->m_iTimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wrk->IsRunning() && wrk->GetState() != workstate::WAIT)
|
||||
wrk->DoWork();
|
||||
} catch (const std::exception& exc) {
|
||||
wrk->OnException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = m_Workers.begin(); it != m_Workers.end();)
|
||||
{
|
||||
Worker* wrk = it->m_pWorker;
|
||||
if (!wrk->IsRunning())
|
||||
{
|
||||
WorkerDestroy(wrk);
|
||||
m_Workers.erase(it);
|
||||
}
|
||||
else ++it;
|
||||
}
|
||||
|
||||
if (GetStage() == 0)
|
||||
{
|
||||
while(m_Workers.size() < m_uMaxWorkers)
|
||||
{
|
||||
Worker* wrk = m_Create(GetData());
|
||||
if (wrk)
|
||||
WorkerStart(wrk);
|
||||
else
|
||||
{
|
||||
Continue(1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (GetStage() == 1 && m_Workers.empty())
|
||||
Finish();
|
||||
}
|
||||
|
||||
void Scheduler::WorkerStart(Worker* wrk)
|
||||
{
|
||||
printf("WorkerStart %p\n", wrk);
|
||||
wrk->EnableThink(false);
|
||||
|
||||
schedworker_t sched = { wrk, 0 };
|
||||
m_Workers.push_back(sched);
|
||||
}
|
||||
|
||||
void Scheduler::WorkerUpdate(Worker* wrk)
|
||||
{
|
||||
printf("WorkerUpdate %p\n", wrk);
|
||||
wrk->Update();
|
||||
|
||||
}
|
||||
|
||||
void Scheduler::WorkerDestroy(Worker* wrk)
|
||||
{
|
||||
printf("WorkerDestroy %p %s\n", wrk, wrk->GetExitMessage().c_str());
|
||||
delete wrk;
|
||||
}
|
||||
36
scheduler.h
Normal file
36
scheduler.h
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef __SCHEDULER_H
|
||||
#define __SCHEDULER_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "worker.h"
|
||||
|
||||
#define SCHEDULER_DELAY 100
|
||||
|
||||
typedef struct {
|
||||
Worker* m_pWorker;
|
||||
int m_iTimer;
|
||||
} schedworker_t;
|
||||
|
||||
typedef std::function<Worker*(void*)> CreateFunc;
|
||||
|
||||
class Scheduler : public ThreadWorker
|
||||
{
|
||||
public:
|
||||
Scheduler(CreateFunc func, unsigned uMaxWorkers);
|
||||
~Scheduler();
|
||||
|
||||
void DoControl() override;
|
||||
void DoWork() override;
|
||||
protected:
|
||||
void WorkerStart(Worker* wrk);
|
||||
void WorkerUpdate(Worker* wrk);
|
||||
void WorkerDestroy(Worker* wrk);
|
||||
private:
|
||||
CreateFunc m_Create;
|
||||
unsigned m_uMaxWorkers;
|
||||
std::vector<schedworker_t> m_Workers;
|
||||
};
|
||||
|
||||
#endif
|
||||
272
worker.cpp
Normal file
272
worker.cpp
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
#include "worker.h"
|
||||
|
||||
/* WaitObject */
|
||||
|
||||
WaitObject::WaitObject()
|
||||
: m_Type(WaitObject::NoWait)
|
||||
{
|
||||
m_lInterval = 0;
|
||||
m_Func = NULL;
|
||||
m_pData = NULL;
|
||||
}
|
||||
|
||||
WaitObject::WaitObject(long lInterval)
|
||||
: m_Type(WaitObject::WaitInterval)
|
||||
{
|
||||
m_lInterval = lInterval > 0 ? lInterval : 0;
|
||||
m_Func = NULL;
|
||||
m_pData = NULL;
|
||||
}
|
||||
|
||||
WaitObject::WaitObject(WaitFunc func, void* data, long delay)
|
||||
: m_Type(WaitObject::WaitFunction)
|
||||
{
|
||||
m_lInterval = delay > 0 ? delay : 0;
|
||||
m_Func = func;
|
||||
m_pData = data;
|
||||
}
|
||||
|
||||
const WaitObject NoWait = WaitObject();
|
||||
const WaitObject DefWait = WaitObject(100);
|
||||
|
||||
/* Worker */
|
||||
|
||||
Worker::Worker()
|
||||
{
|
||||
m_pData = NULL;
|
||||
m_bThink = false;
|
||||
m_iStage = 0;
|
||||
m_State = workstate::INIT;
|
||||
m_bRunning = false;
|
||||
}
|
||||
|
||||
Worker::~Worker()
|
||||
{
|
||||
}
|
||||
|
||||
void Worker::SetName(const std::wstring& name)
|
||||
{
|
||||
m_Name = name;
|
||||
}
|
||||
|
||||
std::wstring Worker::GetName() const
|
||||
{
|
||||
return m_Name;
|
||||
}
|
||||
|
||||
void Worker::SetData(void* data)
|
||||
{
|
||||
m_pData = data;
|
||||
}
|
||||
|
||||
void* Worker::GetData() const
|
||||
{
|
||||
return m_pData;
|
||||
}
|
||||
|
||||
void Worker::SetControlFunction(WorkerFunc func)
|
||||
{
|
||||
m_Control = func;
|
||||
}
|
||||
|
||||
void Worker::SetWorkerFunction(WorkerFunc func)
|
||||
{
|
||||
m_Work = func;
|
||||
}
|
||||
|
||||
void Worker::SetUpdateFunction(WorkerFunc func)
|
||||
{
|
||||
m_Update = func;
|
||||
}
|
||||
|
||||
void Worker::SetState(workstate state, bool bRunning)
|
||||
{
|
||||
if (m_State == workstate::WAIT && state != m_State)
|
||||
m_Wait = NoWait;
|
||||
|
||||
m_State = state;
|
||||
m_bRunning = bRunning;
|
||||
}
|
||||
|
||||
workstate Worker::GetState() const
|
||||
{
|
||||
return m_State;
|
||||
}
|
||||
|
||||
bool Worker::IsRunning() const
|
||||
{
|
||||
return m_bRunning;
|
||||
}
|
||||
|
||||
std::string& Worker::GetExitMessage()
|
||||
{
|
||||
return m_Msg;
|
||||
}
|
||||
|
||||
WaitObject& Worker::GetWait()
|
||||
{
|
||||
return m_Wait;
|
||||
}
|
||||
|
||||
void Worker::SetStage(int stage)
|
||||
{
|
||||
m_iStage = stage;
|
||||
}
|
||||
|
||||
int Worker::GetStage() const
|
||||
{
|
||||
return m_iStage;
|
||||
}
|
||||
|
||||
int Worker::GetProgress() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Worker::EnableThink(bool bThink)
|
||||
{
|
||||
m_bThink = bThink;
|
||||
}
|
||||
|
||||
void Worker::Start()
|
||||
{
|
||||
SetState(workstate::INIT, true);
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
void Worker::Fail(const std::string& msg)
|
||||
{
|
||||
SetState(workstate::FAIL, false);
|
||||
m_Msg = msg;
|
||||
}
|
||||
|
||||
void Worker::Wait(const WaitObject& obj)
|
||||
{
|
||||
SetState(workstate::WAIT, true);
|
||||
m_Wait = obj;
|
||||
}
|
||||
|
||||
void Worker::Continue(int nextStage)
|
||||
{
|
||||
SetState(workstate::RUNNING, true);
|
||||
if (nextStage != -1)
|
||||
SetStage(nextStage);
|
||||
}
|
||||
|
||||
void Worker::Finish()
|
||||
{
|
||||
SetState(workstate::FINISH, false);
|
||||
}
|
||||
|
||||
void Worker::OnException(const std::exception& exc)
|
||||
{
|
||||
fprintf(stderr, "%s\n", exc.what());
|
||||
Fail(exc.what());
|
||||
}
|
||||
|
||||
void Worker::DoControl()
|
||||
{
|
||||
if (m_Control)
|
||||
m_Control(this);
|
||||
}
|
||||
|
||||
void Worker::DoWork()
|
||||
{
|
||||
if (m_Work)
|
||||
m_Work(this);
|
||||
}
|
||||
|
||||
void Worker::Update()
|
||||
{
|
||||
try {
|
||||
if (m_Update)
|
||||
m_Update(this);
|
||||
|
||||
DoControl();
|
||||
if (m_bThink)
|
||||
Think();
|
||||
|
||||
if (IsRunning() && GetState() != workstate::WAIT)
|
||||
DoWork();
|
||||
} catch (const std::exception& exc) {
|
||||
OnException(exc);
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::Think()
|
||||
{
|
||||
switch(GetState())
|
||||
{
|
||||
case workstate::WAIT: DoWait(); break;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::DoWait()
|
||||
{
|
||||
WaitObject& obj = GetWait();
|
||||
switch(obj.m_Type)
|
||||
{
|
||||
case WaitObject::NoWait:
|
||||
SetState(workstate::RUNNING, true);
|
||||
break;
|
||||
case WaitObject::WaitInterval:
|
||||
Sleep(obj.m_lInterval);
|
||||
SetState(workstate::RUNNING, true);
|
||||
break;
|
||||
case WaitObject::WaitFunction:
|
||||
if (obj.m_Func(obj.m_pData))
|
||||
SetState(workstate::RUNNING, true);
|
||||
else Sleep(obj.m_lInterval);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Worker::Run()
|
||||
{
|
||||
do {
|
||||
Update();
|
||||
} while (IsRunning());
|
||||
}
|
||||
|
||||
/* ThreadWorker */
|
||||
|
||||
ThreadWorker::ThreadWorker()
|
||||
{
|
||||
m_hThread = INVALID_HANDLE_VALUE;
|
||||
m_ulThreadId = 0;
|
||||
}
|
||||
|
||||
ThreadWorker::~ThreadWorker()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned long ThreadWorker::GetThreadId() const
|
||||
{
|
||||
return m_ulThreadId;
|
||||
}
|
||||
|
||||
DWORD WINAPI ThreadWorker::_ThreadWorker(LPVOID lpArg)
|
||||
{
|
||||
ThreadWorker* wrk = (ThreadWorker*)lpArg;
|
||||
|
||||
wrk->SetState(workstate::INIT, false);
|
||||
wrk->EnableThink(true);
|
||||
wrk->Update();
|
||||
|
||||
wrk->Run();
|
||||
return !(wrk->GetState() == workstate::FINISH);
|
||||
}
|
||||
|
||||
void ThreadWorker::Start()
|
||||
{
|
||||
DWORD dwTid;
|
||||
m_hThread = CreateThread(NULL, 0, _ThreadWorker, this, 0, &dwTid);
|
||||
m_ulThreadId = dwTid;
|
||||
}
|
||||
|
||||
void ThreadWorker::JoinThread()
|
||||
{
|
||||
WaitForSingleObject(m_hThread, INFINITE);
|
||||
}
|
||||
146
worker.h
Normal file
146
worker.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
#ifndef __WORKER_H
|
||||
#define __WORKER_H
|
||||
|
||||
#include <Windows.h>
|
||||
#include <functional>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
/* WaitObject */
|
||||
|
||||
typedef std::function<bool(void*)> WaitFunc;
|
||||
|
||||
class WaitObject
|
||||
{
|
||||
public:
|
||||
enum : int { NoWait, WaitInterval, WaitFunction };
|
||||
|
||||
WaitObject();
|
||||
WaitObject(long lInterval);
|
||||
WaitObject(WaitFunc func, void* data, long delay);
|
||||
|
||||
int m_Type;
|
||||
long m_lInterval;
|
||||
WaitFunc m_Func;
|
||||
void* m_pData;
|
||||
};
|
||||
|
||||
extern const WaitObject NoWait;
|
||||
extern const WaitObject DefWait;
|
||||
|
||||
/* Worker */
|
||||
|
||||
class Worker;
|
||||
|
||||
/*typedef enum class {
|
||||
STATE_FAIL = -1,
|
||||
STATE_INIT,
|
||||
STATE_WAIT,
|
||||
STATE_RUNNING,
|
||||
STATE_FINISH,
|
||||
} workstate;*/
|
||||
/*enum class workstate {
|
||||
STATE_FAIL = -1,
|
||||
STATE_INIT,
|
||||
STATE_WAIT,
|
||||
STATE_RUNNING,
|
||||
STATE_FINISH
|
||||
};*/
|
||||
|
||||
enum class workstate {
|
||||
FAIL = -1,
|
||||
INIT,
|
||||
WAIT,
|
||||
RUNNING,
|
||||
FINISH
|
||||
};
|
||||
|
||||
typedef std::function<void(Worker*)> WorkerFunc;
|
||||
|
||||
class Worker
|
||||
{
|
||||
public:
|
||||
Worker();
|
||||
virtual ~Worker();
|
||||
|
||||
virtual void SetName(const std::wstring& name);
|
||||
virtual std::wstring GetName() const;
|
||||
|
||||
virtual void SetData(void* pData);
|
||||
virtual void* GetData() const;
|
||||
|
||||
virtual void SetControlFunction(WorkerFunc func);
|
||||
virtual void SetWorkerFunction(WorkerFunc func);
|
||||
virtual void SetUpdateFunction(WorkerFunc func);
|
||||
|
||||
virtual void SetState(workstate state, bool bRunning);
|
||||
|
||||
virtual workstate GetState() const;
|
||||
virtual bool IsRunning() const;
|
||||
|
||||
virtual std::string& GetExitMessage();
|
||||
virtual WaitObject& GetWait();
|
||||
|
||||
virtual void SetStage(int stage);
|
||||
virtual int GetStage() const;
|
||||
|
||||
virtual int GetProgress() const;
|
||||
|
||||
virtual void EnableThink(bool bThink);
|
||||
virtual void Start();
|
||||
|
||||
virtual void Fail(const std::string& msg);
|
||||
virtual void Wait(const WaitObject& obj);
|
||||
virtual void Continue(int nextStage = -1);
|
||||
|
||||
virtual void Finish();
|
||||
|
||||
virtual void OnException(const std::exception& exc);
|
||||
|
||||
virtual void DoControl();
|
||||
virtual void DoWork();
|
||||
protected:
|
||||
virtual void Think();
|
||||
void DoWait();
|
||||
public:
|
||||
virtual void Update();
|
||||
virtual void Run();
|
||||
private:
|
||||
std::wstring m_Name;
|
||||
|
||||
void* m_pData;
|
||||
|
||||
WorkerFunc m_Control;
|
||||
WorkerFunc m_Work;
|
||||
WorkerFunc m_Update;
|
||||
|
||||
workstate m_State;
|
||||
bool m_bRunning;
|
||||
int m_iStage;
|
||||
std::string m_Msg;
|
||||
|
||||
WaitObject m_Wait;
|
||||
|
||||
bool m_bThink;
|
||||
};
|
||||
|
||||
/* ThreadWorker */
|
||||
|
||||
class ThreadWorker : public Worker
|
||||
{
|
||||
public:
|
||||
ThreadWorker();
|
||||
virtual ~ThreadWorker();
|
||||
|
||||
virtual unsigned long GetThreadId() const;
|
||||
|
||||
virtual void Start();
|
||||
void JoinThread();
|
||||
private:
|
||||
static DWORD WINAPI _ThreadWorker(LPVOID);
|
||||
|
||||
unsigned long m_ulThreadId;
|
||||
HANDLE m_hThread;
|
||||
};
|
||||
|
||||
#endif
|
||||
Loading…
Add table
Reference in a new issue