/* ----------------------------------------------------------------------------- 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 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 > class Controller { public: struct Command { Atomic32 dispose; virtual void Execute(Target *target) = 0; Command() : dispose(1) {} virtual ~Command() {} }; template struct CommandWithResult : public Command { Future future_result; CommandWithResult() { this->dispose.Set(0); } }; private: struct WorkerThread : public Thread { Target *target; Atomic32 running; Mutex command_mutex; Event command_event; AutoList 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 Result QueueCommand(CommandWithResult *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__