ultimatepp/bazaar/MtAlt/MtAlt.h
mrjt 1276dbc3ff Altenative MultiThreading package, plus example added to Bazaar on behalf of Pavel Ostapenko (Mindtraveller)
git-svn-id: svn://ultimatepp.org/upp/trunk@1395 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2009-07-10 15:42:31 +00:00

352 lines
7.8 KiB
C++

#ifndef _CORE_alt_MTalt_h_
#define _CORE_alt_MTalt_h_
#ifndef flagMT
#error Please add 'MT' to build flags
#endif
#include <Core/Core.h>
using namespace Upp;
dword rdtsc();
class CallbackQueue : private NoCopy
{
public:
CallbackQueue(int _id = 0)
:shuttingDown(false)
,started(false)
,id(_id)
{
Vector<CallbackQueue *> &q = queues.GetAdd(id);
q << this;
}
virtual ~CallbackQueue()
{
qMutex.Enter();
queue.Clear();
qMutex.Leave();
Vector<CallbackQueue *> &q = queues.Get(id);
for (int i=0; i<q.GetCount(); ++i)
{
if (q[i] == this)
{
q.Remove(i);
break;
}
}
}
#define LOCK_ADD_UNLOCK \
qMutex.Enter(); \
queue.AddTail(e); \
qMutex.Leave(); \
qSemaphore.Release();
void ClearQueue()
{
qMutex.Enter();
queue.Clear();
qMutex.Leave();
}
template<class OBJECT>
void Request(void (OBJECT::*m)())
{
Element0<OBJECT> *e = new Element0<OBJECT>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1>
void Request(void (OBJECT::*m)(pick_ P1 &), pick_ P1 &p1)
{
Element1<OBJECT, P1> *e = new Element1<OBJECT, P1>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1>
void Request(void (OBJECT::*m)(P1), P1 p1)
{
Element1c<OBJECT, P1> *e = new Element1c<OBJECT, P1>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1, class P2>
void Request(void (OBJECT::*m)(pick_ P1 &,pick_ P2 &), pick_ P1 &p1, pick_ P2 &p2)
{
Element2<OBJECT, P1, P2> *e = new Element2<OBJECT, P1, P2>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
e->p2 = p2;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1, class P2>
void Request(void (OBJECT::*m)(P1,P2), P1 p1, P2 p2)
{
Element2c<OBJECT, P1, P2> *e = new Element2c<OBJECT, P1, P2>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
e->p2 = p2;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1, class P2, class P3>
void Request(void (OBJECT::*m)(pick_ P1 &, pick_ P2 &, pick_ P3 &), pick_ P1 &p1, pick_ P2 &p2, pick_ P3 &p3)
{
Element3<OBJECT, P1, P2, P3> *e = new Element3<OBJECT, P1, P2, P3>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
e->p2 = p2;
e->p3 = p3;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1, class P2, class P3>
void Request(void (OBJECT::*m)(P1,P2,P3), P1 p1, P2 p2, P3 p3)
{
Element3c<OBJECT, P1, P2, P3> *e = new Element3c<OBJECT, P1, P2, P3>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
e->p2 = p2;
e->p3 = p3;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1, class P2, class P3, class P4>
void Request(void (OBJECT::*m)(pick_ P1 &, pick_ P2 &, pick_ P3 &, pick_ P4 &), pick_ P1 &p1, pick_ P2 &p2, pick_ P3 &p3, pick_ P4 &p4)
{
Element4<OBJECT, P1, P2, P3, P4> *e = new Element4<OBJECT, P1, P2, P3, P4>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
e->p2 = p2;
e->p3 = p3;
e->p4 = p4;
LOCK_ADD_UNLOCK;
}
template<class OBJECT, class P1, class P2, class P3, class P4>
void Request(void (OBJECT::*m)(P1,P2,P3,P4), P1 p1, P2 p2, P3 p3, P4 p4)
{
Element4c<OBJECT, P1, P2, P3, P4> *e = new Element4c<OBJECT, P1, P2, P3, P4>;
e->caller = static_cast<OBJECT *>(this);
e->m = m;
e->p1 = p1;
e->p2 = p2;
e->p3 = p3;
e->p4 = p4;
LOCK_ADD_UNLOCK;
}
void DoTasks()
{
while (!IsShutdown())
if (!Execute())
return;
}
void WaitDoTasksInf()
{
while (!IsShutdown())
{
qSemaphore.Wait();
Execute();
}
}
int GetTasksCount() {qMutex.Enter(); int out=queue.GetCount(); qMutex.Leave(); return out;}
bool IsShutdown() {return shuttingDown;}
bool IsStarted() {return started;}
static void StartAll(int id = 0)
{
Vector<CallbackQueue *> &q = queues.GetAdd(id);
for (int i=0; i<q.GetCount(); ++i)
q[i]->Start();
}
static void ShutdownAll(int id = 0)
{
Vector<CallbackQueue *> &q = queues.GetAdd(id);
for (int i=0; i<q.GetCount(); ++i)
q[i]->Shutdown();
}
virtual void Start() {started = true;}
virtual void Shutdown()
{
if (!IsStarted() || IsShutdown())
return;
shuttingDown = true;
Request(&CallbackQueue::DoNothingJustAwake);
}
private:
static VectorMap<int, Vector<CallbackQueue *> > queues;
bool Execute()
{
qMutex.Enter();
if (queue.IsEmpty())
{
qMutex.Leave();
return false;
}
Element *e = queue.DetachHead();
qMutex.Leave();
e->Execute();
delete e;
return true;
}
struct Element
{
virtual ~Element() {}
virtual void Execute() = 0;
void *caller;
};
template<class OBJECT>
struct Element0 : public Element
{
virtual ~Element0() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)();}
void (OBJECT::*m)();
};
template<class OBJECT, class P1>
struct Element1 : public Element
{
virtual ~Element1() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1);}
void (OBJECT::*m)(pick_ P1 &p1);
P1 p1;
};
template<class OBJECT, class P1>
struct Element1c : public Element
{
virtual ~Element1c() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1);}
void (OBJECT::*m)(P1 p1);
P1 p1;
};
template<class OBJECT, class P1, class P2>
struct Element2 : public Element
{
virtual ~Element2() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1,p2);}
void (OBJECT::*m)(pick_ P1 &p1, pick_ P2 &p2);
P1 p1;
P2 p2;
};
template<class OBJECT, class P1, class P2>
struct Element2c : public Element
{
virtual ~Element2c() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1,p2);}
void (OBJECT::*m)(P1 p1, P2 p2);
P1 p1;
P2 p2;
};
template<class OBJECT, class P1, class P2, class P3>
struct Element3 : public Element
{
virtual ~Element3() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1,p2,p3);}
void (OBJECT::*m)(pick_ P1 &p1, pick_ P2 &p2, pick_ P3 &p3);
P1 p1;
P2 p2;
P3 p3;
};
template<class OBJECT, class P1, class P2, class P3>
struct Element3c : public Element
{
virtual ~Element3c() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1,p2,p3);}
void (OBJECT::*m)(P1 p1, P2 p2, P3 p3);
P1 p1;
P2 p2;
P3 p3;
};
template<class OBJECT, class P1, class P2, class P3, class P4>
struct Element4 : public Element
{
virtual ~Element4() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1,p2,p3,p4);}
void (OBJECT::*m)(pick_ P1 &p1, pick_ P2 &p2, pick_ P3 &p3, pick_ P4 &p4);
P1 p1;
P2 p2;
P3 p3;
P4 p4;
};
template<class OBJECT, class P1, class P2, class P3, class P4>
struct Element4c : public Element
{
virtual ~Element4c() {}
virtual void Execute() {((static_cast<OBJECT *>(caller))->*m)(p1,p2,p3,p4);}
void (OBJECT::*m)(P1 p1, P2 p2, P3 p3, P4 p4);
P1 p1;
P2 p2;
P3 p3;
P4 p4;
};
void DoNothingJustAwake(){}
BiArray<Element> queue;
Mutex qMutex;
Semaphore qSemaphore;
bool shuttingDown;
bool started;
int id;
};
class CallbackThread : public CallbackQueue, protected Thread
{
public:
CallbackThread(int id = 0) :CallbackQueue(id) {}
virtual ~CallbackThread() {Shutdown();}
virtual void Start()
{
CallbackQueue::Start();
Thread::Run(callback(this, &CallbackThread::Run));
}
virtual void Shutdown()
{
if (!IsStarted() || IsShutdown())
return;
CallbackQueue::Shutdown();
Wait();
}
private:
void Run() {WaitDoTasksInf();}
};
#endif