diff --git a/bazaar/MtAlt/MtAlt.cpp b/bazaar/MtAlt/MtAlt.cpp new file mode 100644 index 000000000..84833685d --- /dev/null +++ b/bazaar/MtAlt/MtAlt.cpp @@ -0,0 +1,3 @@ +#include "MtAlt.h" + +VectorMap > CallbackQueue::queues; diff --git a/bazaar/MtAlt/MtAlt.h b/bazaar/MtAlt/MtAlt.h new file mode 100644 index 000000000..b26c8ee1d --- /dev/null +++ b/bazaar/MtAlt/MtAlt.h @@ -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 +using namespace Upp; + +dword rdtsc(); + +class CallbackQueue : private NoCopy +{ +public: + CallbackQueue(int _id = 0) + :shuttingDown(false) + ,started(false) + ,id(_id) + { + Vector &q = queues.GetAdd(id); + q << this; + } + + virtual ~CallbackQueue() + { + qMutex.Enter(); + queue.Clear(); + qMutex.Leave(); + + Vector &q = queues.Get(id); + for (int i=0; i + void Request(void (OBJECT::*m)()) + { + Element0 *e = new Element0; + e->caller = static_cast(this); + e->m = m; + LOCK_ADD_UNLOCK; + } + + template + void Request(void (OBJECT::*m)(pick_ P1 &), pick_ P1 &p1) + { + Element1 *e = new Element1; + e->caller = static_cast(this); + e->m = m; + e->p1 = p1; + LOCK_ADD_UNLOCK; + } + + template + void Request(void (OBJECT::*m)(P1), P1 p1) + { + Element1c *e = new Element1c; + e->caller = static_cast(this); + e->m = m; + e->p1 = p1; + LOCK_ADD_UNLOCK; + } + + template + void Request(void (OBJECT::*m)(pick_ P1 &,pick_ P2 &), pick_ P1 &p1, pick_ P2 &p2) + { + Element2 *e = new Element2; + e->caller = static_cast(this); + e->m = m; + e->p1 = p1; + e->p2 = p2; + LOCK_ADD_UNLOCK; + } + + template + void Request(void (OBJECT::*m)(P1,P2), P1 p1, P2 p2) + { + Element2c *e = new Element2c; + e->caller = static_cast(this); + e->m = m; + e->p1 = p1; + e->p2 = p2; + LOCK_ADD_UNLOCK; + } + + template + void Request(void (OBJECT::*m)(pick_ P1 &, pick_ P2 &, pick_ P3 &), pick_ P1 &p1, pick_ P2 &p2, pick_ P3 &p3) + { + Element3 *e = new Element3; + e->caller = static_cast(this); + e->m = m; + e->p1 = p1; + e->p2 = p2; + e->p3 = p3; + LOCK_ADD_UNLOCK; + } + + template + void Request(void (OBJECT::*m)(P1,P2,P3), P1 p1, P2 p2, P3 p3) + { + Element3c *e = new Element3c; + e->caller = static_cast(this); + e->m = m; + e->p1 = p1; + e->p2 = p2; + e->p3 = p3; + LOCK_ADD_UNLOCK; + } + + template + 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 *e = new Element4; + e->caller = static_cast(this); + e->m = m; + e->p1 = p1; + e->p2 = p2; + e->p3 = p3; + e->p4 = p4; + LOCK_ADD_UNLOCK; + } + + template + void Request(void (OBJECT::*m)(P1,P2,P3,P4), P1 p1, P2 p2, P3 p3, P4 p4) + { + Element4c *e = new Element4c; + e->caller = static_cast(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 &q = queues.GetAdd(id); + for (int i=0; iStart(); + } + + static void ShutdownAll(int id = 0) + { + Vector &q = queues.GetAdd(id); + for (int i=0; iShutdown(); + } + + virtual void Start() {started = true;} + virtual void Shutdown() + { + if (!IsStarted() || IsShutdown()) + return; + shuttingDown = true; + Request(&CallbackQueue::DoNothingJustAwake); + } + +private: + static VectorMap > 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 + struct Element0 : public Element + { + virtual ~Element0() {} + virtual void Execute() {((static_cast(caller))->*m)();} + void (OBJECT::*m)(); + }; + + template + struct Element1 : public Element + { + virtual ~Element1() {} + virtual void Execute() {((static_cast(caller))->*m)(p1);} + void (OBJECT::*m)(pick_ P1 &p1); + P1 p1; + }; + + template + struct Element1c : public Element + { + virtual ~Element1c() {} + virtual void Execute() {((static_cast(caller))->*m)(p1);} + void (OBJECT::*m)(P1 p1); + P1 p1; + }; + + template + struct Element2 : public Element + { + virtual ~Element2() {} + virtual void Execute() {((static_cast(caller))->*m)(p1,p2);} + void (OBJECT::*m)(pick_ P1 &p1, pick_ P2 &p2); + P1 p1; + P2 p2; + }; + + template + struct Element2c : public Element + { + virtual ~Element2c() {} + virtual void Execute() {((static_cast(caller))->*m)(p1,p2);} + void (OBJECT::*m)(P1 p1, P2 p2); + P1 p1; + P2 p2; + }; + + template + struct Element3 : public Element + { + virtual ~Element3() {} + virtual void Execute() {((static_cast(caller))->*m)(p1,p2,p3);} + void (OBJECT::*m)(pick_ P1 &p1, pick_ P2 &p2, pick_ P3 &p3); + P1 p1; + P2 p2; + P3 p3; + }; + + template + struct Element3c : public Element + { + virtual ~Element3c() {} + virtual void Execute() {((static_cast(caller))->*m)(p1,p2,p3);} + void (OBJECT::*m)(P1 p1, P2 p2, P3 p3); + P1 p1; + P2 p2; + P3 p3; + }; + + template + struct Element4 : public Element + { + virtual ~Element4() {} + virtual void Execute() {((static_cast(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 + struct Element4c : public Element + { + virtual ~Element4c() {} + virtual void Execute() {((static_cast(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 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 diff --git a/bazaar/MtAlt/MtAlt.upp b/bazaar/MtAlt/MtAlt.upp new file mode 100644 index 000000000..e443e0451 --- /dev/null +++ b/bazaar/MtAlt/MtAlt.upp @@ -0,0 +1,12 @@ +description "Alternative multithreading by Pavel Ostapenko\377"; + +uses + Core; + +file + MtAlt.cpp, + MtAlt.h; + +mainconfig + "" = "MT"; + diff --git a/bazaar/MtAlt/init b/bazaar/MtAlt/init new file mode 100644 index 000000000..50b9bbdc9 --- /dev/null +++ b/bazaar/MtAlt/init @@ -0,0 +1,4 @@ +#ifndef _MtAlt_icpp_init_stub +#define _MtAlt_icpp_init_stub +#include "Core/init" +#endif diff --git a/bazaar/MtAltExample1/Main.cpp b/bazaar/MtAltExample1/Main.cpp new file mode 100644 index 000000000..e8a51b9e7 --- /dev/null +++ b/bazaar/MtAltExample1/Main.cpp @@ -0,0 +1,54 @@ +#include +#include +#include "Worker.h" +using namespace Upp; + +#define LAYOUTFILE +#include + +//thread GUI (main application thread) +class MainWindow : public WithMainWindowLayout, 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(); +} + diff --git a/bazaar/MtAltExample1/MainWindow.lay b/bazaar/MtAltExample1/MainWindow.lay new file mode 100644 index 000000000..a2177ea73 --- /dev/null +++ b/bazaar/MtAltExample1/MainWindow.lay @@ -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 + diff --git a/bazaar/MtAltExample1/MtAltExample1.upp b/bazaar/MtAltExample1/MtAltExample1.upp new file mode 100644 index 000000000..ba9bf084c --- /dev/null +++ b/bazaar/MtAltExample1/MtAltExample1.upp @@ -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"; + diff --git a/bazaar/MtAltExample1/Worker.h b/bazaar/MtAltExample1/Worker.h new file mode 100644 index 000000000..4005bdfc5 --- /dev/null +++ b/bazaar/MtAltExample1/Worker.h @@ -0,0 +1,31 @@ +#ifndef _MtAltExample1_OtherThreadClasses_h_ +#define _MtAltExample1_OtherThreadClasses_h_ + +#include +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 diff --git a/bazaar/MtAltExample1/init b/bazaar/MtAltExample1/init new file mode 100644 index 000000000..c09a42d4c --- /dev/null +++ b/bazaar/MtAltExample1/init @@ -0,0 +1,5 @@ +#ifndef _MtAltExample1_icpp_init_stub +#define _MtAltExample1_icpp_init_stub +#include "CtrlLib/init" +#include "MtAlt/init" +#endif