136 lines
2.9 KiB
C++
136 lines
2.9 KiB
C++
/* -----------------------------------------------------------------------------
|
|
GSFramework
|
|
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
|
----------------------------------------------------------------------------- */
|
|
|
|
|
|
#ifndef __THREAD_CONTROLLER__
|
|
#define __THREAD_CONTROLLER__
|
|
|
|
|
|
#include "thread/atomic_value.h"
|
|
#include "thread/thread_event.h"
|
|
#include "thread/future.h"
|
|
#include "thread/thread.h"
|
|
#include "thread/mutex.h"
|
|
#include "container/nlist.h"
|
|
|
|
|
|
namespace GS {
|
|
namespace Threading {
|
|
|
|
//------------------------------------------------------------------------------
|
|
template <typename Target> struct DefaultControllerPolicy
|
|
{
|
|
static const bool use_event = true; // use thread event to sleep the worker thread
|
|
static const bool own_target = false; // the controller owns the target object and is responsible for deleting it
|
|
|
|
static void Update(Target *) {}
|
|
};
|
|
|
|
template <typename Target, class Policy = DefaultControllerPolicy <Target> > class Controller
|
|
{
|
|
public:
|
|
|
|
struct Command
|
|
{
|
|
Atomic32 dispose;
|
|
virtual void Execute(Target *target) = 0;
|
|
|
|
Command() : dispose(1) {}
|
|
virtual ~Command() {}
|
|
};
|
|
|
|
template <class Result> struct CommandWithResult : public Command
|
|
{
|
|
Future <Result> future_result;
|
|
CommandWithResult() { this->dispose.Set(0); }
|
|
};
|
|
|
|
private:
|
|
|
|
struct WorkerThread : public Thread
|
|
{
|
|
Target *target;
|
|
|
|
Atomic32 running;
|
|
|
|
Mutex command_mutex;
|
|
Event command_event;
|
|
|
|
AutoList <Command *> command_queue;
|
|
|
|
void Execute()
|
|
{
|
|
forever
|
|
{
|
|
Policy::Update(target);
|
|
{
|
|
MutexLock lock(&command_mutex);
|
|
while (command_queue.GetCount() > 0)
|
|
{
|
|
command_queue[0]->Execute(target);
|
|
while (command_queue[0]->dispose.Get() != 1)
|
|
; // spin lock on command dispose flag
|
|
command_queue.RemoveAt(0);
|
|
}
|
|
if (running.Get() != 1)
|
|
break;
|
|
}
|
|
if (Policy::use_event)
|
|
command_event.Wait();
|
|
}
|
|
running.Set(0);
|
|
}
|
|
void Stop()
|
|
{
|
|
running.Set(2);
|
|
if (Policy::use_event)
|
|
command_event.Trigger();
|
|
while (running.Get() != 0); // spinlock
|
|
}
|
|
|
|
WorkerThread(Target *t) : target(t), running(1) {}
|
|
~WorkerThread()
|
|
{
|
|
if (Policy::own_target)
|
|
delete target;
|
|
}
|
|
};
|
|
|
|
WorkerThread worker;
|
|
|
|
public:
|
|
|
|
void QueueCommand(Command *c)
|
|
{
|
|
{
|
|
MutexLock lock(&worker.command_mutex);
|
|
worker.command_queue.Append(c);
|
|
}
|
|
worker.command_event.Trigger();
|
|
}
|
|
template <class Result> Result QueueCommand(CommandWithResult <Result> *c)
|
|
{
|
|
QueueCommand((Command *)c);
|
|
|
|
Result result = c->future_result.Get(); // wait for command result
|
|
c->dispose.Set(1); // flag command disposal
|
|
return result; // return result
|
|
}
|
|
|
|
bool Start()
|
|
{ return worker.Start(); }
|
|
void Stop()
|
|
{ worker.Stop(); }
|
|
|
|
Controller(Target *t) : worker(t) {}
|
|
};
|
|
//------------------------------------------------------------------------------
|
|
|
|
} // Threading
|
|
} // GS
|
|
|
|
|
|
#endif // __THREAD_CONTROLLER__
|