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
This commit is contained in:
mrjt 2009-07-10 15:42:31 +00:00
parent cdf8927206
commit 1276dbc3ff
9 changed files with 482 additions and 0 deletions

3
bazaar/MtAlt/MtAlt.cpp Normal file
View file

@ -0,0 +1,3 @@
#include "MtAlt.h"
VectorMap<int, Vector<CallbackQueue *> > CallbackQueue::queues;

352
bazaar/MtAlt/MtAlt.h Normal file
View file

@ -0,0 +1,352 @@
#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

12
bazaar/MtAlt/MtAlt.upp Normal file
View file

@ -0,0 +1,12 @@
description "Alternative multithreading by Pavel Ostapenko\377";
uses
Core;
file
MtAlt.cpp,
MtAlt.h;
mainconfig
"" = "MT";

4
bazaar/MtAlt/init Normal file
View file

@ -0,0 +1,4 @@
#ifndef _MtAlt_icpp_init_stub
#define _MtAlt_icpp_init_stub
#include "Core/init"
#endif

View file

@ -0,0 +1,54 @@
#include <CtrlLib/CtrlLib.h>
#include <MtAlt/MtAlt.h>
#include "Worker.h"
using namespace Upp;
#define LAYOUTFILE <MtAltExample1/MainWindow.lay>
#include <CtrlCore/lay.h>
//thread GUI (main application thread)
class MainWindow : public WithMainWindowLayout<TopWindow>, public CallbackQueue, public Worker::Notify
{
public: //thread GUI
MainWindow();
public: //thread Worker
virtual void OnWork2Result(int x1, int x2, String s) {Request(&MainWindow::Work2Result,x1,x2,s);}
private:
void Work1() {worker.Request(&Worker::DoWork1);}
void Work2() {worker.Request(&Worker::DoWork2);}
void Work2Result(int x1, int x2, String s)
{
log.Set(log.Get()+Format("Worker::Work2 %d, %d, %s\n", x1,x2,s));
}
void DoTasksAndStatistics();
Worker worker;
};
MainWindow::MainWindow()
:worker(this)
{
CtrlLayout(*this);
button1 <<= callback(this, &MainWindow::Work1);
button2 <<= callback(this, &MainWindow::Work2);
SetTimeCallback(-200, callback(this, &MainWindow::DoTasksAndStatistics));
worker.Start();
}
void MainWindow::DoTasksAndStatistics()
{
info.SetLabel(Format(" GUI: %d Worker: %d", GetTasksCount(), worker.GetTasksCount()));
DoTasks();
}
GUI_APP_MAIN
{
MainWindow().Sizeable().Run();
}

View file

@ -0,0 +1,7 @@
LAYOUT(MainWindowLayout, 504, 200)
ITEM(DocEdit, log, HSizePosZ(12, 188).VSizePosZ(12, 12))
ITEM(Button, button2, SetLabel(t_("Worker::Work2")).RightPosZ(12, 164).TopPosZ(44, 28))
ITEM(Button, button1, SetLabel(t_("Worker::Work1")).RightPosZ(12, 164).TopPosZ(12, 28))
ITEM(Label, info, SetFrame(BlackFrame()).RightPosZ(12, 164).TopPosZ(168, 19))
END_LAYOUT

View file

@ -0,0 +1,14 @@
description "Example of alternative multithreading by Pavel Ostapenko\377B128,0,0";
uses
CtrlLib,
MtAlt;
file
Main.cpp,
Worker.h,
MainWindow.lay;
mainconfig
"" = "GUI MT";

View file

@ -0,0 +1,31 @@
#ifndef _MtAltExample1_OtherThreadClasses_h_
#define _MtAltExample1_OtherThreadClasses_h_
#include <MtAlt/MtAlt.h>
using namespace Upp;
//new thread 1
class Worker : public CallbackThread
{
public: //thread GUI
class Notify { public: virtual void OnWork2Result(int x1, int x2, String s) = 0; };
Worker(Notify *n) :notify(n) {}
public: //thread 1
void DoWork1()
{
Sleep(300); //do something
}
void DoWork2()
{
Sleep(400); //do something
Time t = GetSysTime();
notify->OnWork2Result((int) Random(10), (int) Random(20), Format(t)); //notify result
}
private:
Notify *notify;
};
#endif

View file

@ -0,0 +1,5 @@
#ifndef _MtAltExample1_icpp_init_stub
#define _MtAltExample1_icpp_init_stub
#include "CtrlLib/init"
#include "MtAlt/init"
#endif