struct Interface { virtual int Ask ( const char * ) = 0; }; struct Work { Interface *gui; }; struct Library { Library ( Work w ) { int a = w.gui->Ask ( "Ok?" ); } }; void Threading ( Work w ) { Library ( w ); } struct Task :MyTask<TopWindow> ,Interface { typedef Task CLASSNAME; Task() { CtrlLayout(*this, "Example" ); Work w; w.gui = this; Thread().Run ( callback1 ( Threading, w ) ); } volatile Atomic q; int Ask_Weird_Hacked ( const char *s, unsigned dummy ) { return q = 1 + PromptYesNo ( String().Cat() << s ); } int Ask ( const char *s ) { //problem here, cannot call PromptYesNo() q = 0; PostCallback ( callback2 ( this, &Task::Ask_Weird_Hacked, s, 0 ) ); while ( !q ) Sleep ( 10 ); return q - 1; } };
void DoAsk(Semaphore *sem, int *result) { *result = PromptYesNo(""); sem->Release(); } struct MyThread { int Ask() { Sempahore sem; int result; PostCallback(callback2(DoAsk, &sem, &result)); sem.Wait(); return result; } }
class GUIThread : public CallbackQueue, public WithMainWindowLayout<TopWindow> { public: GUIThread(); ~GUIThread(); virtual void Init(); virtual void Shutdown(); void HandleIncomingMessages(); public /*sync*/: void RefreshAll(const Drawing &bdr, const ControlGUI &cg); void SetupBathsSettings(Vector<Vector<Value> > rows); }; class IOThread : public CallbackThread, protected RS232 { public: IOThread(); ~IOThread(); virtual void Init(); virtual void Shutdown(); public /*sync*/: void GetAOpState(byte addr); };
GUIThread guiThread; IOThread ioThread; ControlThread controlThread; GUI_APP_MAIN { try { CallbackQueue::InitAll(); CallbackQueue::StartAll(); guiThread.Sizeable().Run(); CallbackQueue::ShutdownAll(); } catch (const Exc &ex) { PromptOK(ex); } }
// i/o therads checks AOp devices and tells their availability to Control thread void IOThread::GetAOpState(byte addr) { for (int i=0; i<attempts; ++i) { protoSend[3] = addr; protoSend[4] = CMD_AOP_STATUS; protoSend.Send(*this, timeout); if (protoRecv.Receive(*this, timeout)) { if ((int)protoRecv[3] != (int)addr) continue; controlThread.Request(&ControlThread::AOpStatus, addr, protoRecv[4]); } } controlThread.Request(&ControlThread::AOpUnavailable, addr); } // Control thread analyzes system state and updates GUI accordingly void ControlThread::SetupDisplayDrawing(bool enableSettings) { static ControlGUI cg; // setting controls to be enabled/disabled // ... // drawing system elements and parameters DrawingDraw d(DISPLAY_W,DISPLAY_H); // ... guiThread.Request(&GUIThread::RefreshAll, static_cast<Drawing>(d), cg); }
Quote: |
Additional question. Suppose we have a kill button in the GUI. void Task::KillButton(). How to kill the thread in this function? We presume the thread is heavy and cannot ping asking the interface for ShouldWeCancelNow() frequently enough to be able to shutdown itself. |
int Semaphore::Wait( int timeout ) { dword result_value; result_value = WaitForSingleObject(handle, timeout); if(result_value == WAIT_FAILED) return(SEMAPHORE_WAIT_ERROR); if(result_value == WAIT_TIMEOUT) return(SEMAPHORE_TIMEOUT); }
int Semaphore::Wait( int timeout ) { dword result_value; result_value = WaitForSingleObject(handle, timeout); if(result_value == WAIT_FAILED) return(SEMAPHORE_WAIT_ERROR); if(result_value == WAIT_TIMEOUT) return(SEMAPHORE_TIMEOUT); }