MathGL can be used to draw plots in parallel with some external calculations. The simplest way for this is the usage of mglDraw class. At this you should enable pthread for widgets by setting enable-pthr-widget=ON
at configure stage (it is set by default).
First, you need to inherit you class from mglDraw
class, define virtual members Draw()
and Calc()
which will draw the plot and proceed calculations. You may want to add the pointer mglWnd *wnd;
to window with plot for interacting with them. Finally, you may add any other data or member functions. The sample class is shown below
class myDraw : public mglDraw { mglPoint pnt; // some variable for changeable data long i; // another variable to be shown mglWnd *wnd; // external window for plotting public: myDraw(mglWnd *w=0) : mglDraw() { wnd=w; } void SetWnd(mglWnd *w) { wnd=w; } int Draw(mglGraph *gr) { gr->Line(mglPoint(),pnt,"Ar2"); char str[16]; snprintf(str,15,"i=%ld",i); gr->Puts(mglPoint(),str); return 0; } void Calc() { for(i=0;;i++) // do calculation { long_calculations();// which can be very long Check(); // check if need pause pnt.Set(2*mgl_rnd()-1,2*mgl_rnd()-1); if(wnd) wnd->Update(); } } } dr;
There is only one issue here. Sometimes you may want to pause calculations to view result carefully, or save state, or change something. So, you need to provide a mechanism for pausing. Class mglDraw
provide function Check();
which check if toolbutton with pause is pressed and wait until it will be released. This function should be called in a "safety" places, where you can pause the calculation (for example, at the end of time step). Also you may add call exit(0);
at the end of Calc();
function for closing window and exit after finishing calculations.
Finally, you need to create a window itself and run calculations.
int main(int argc,char **argv) { mglFLTK gr(&dr,"Multi-threading test"); // create window dr.SetWnd(&gr); // pass window pointer to yours class dr.Run(); // run calculations gr.Run(); // run event loop for window return 0; }
Note, that you can reach the similar functionality without using mglDraw
class (i.e. even for pure C code).
mglFLTK *gr=NULL; // pointer to window void *calc(void *) // function with calculations { mglPoint pnt; // some data for plot for(long i=0;;i++) // do calculation { long_calculations(); // which can be very long pnt.Set(2*mgl_rnd()-1,2*mgl_rnd()-1); if(gr) { gr->Clf(); // make new drawing // draw something gr->Line(mglPoint(),pnt,"Ar2"); char str[16]; snprintf(str,15,"i=%ld",i); gr->Puts(mglPoint(),str); // don't forgot to update window gr->Update(); } } } int main(int argc,char **argv) { static pthread_t thr; pthread_create(&thr,0,calc,0); // create separate thread for calculations pthread_detach(thr); // and detach it gr = new mglFLTK; // now create window gr->Run(); // and run event loop return 0; }
This sample is exactly the same as one with mglDraw
class, but it don’t have functionality for pausing calculations. If you need it then you have to create global mutex (like pthread_mutex_t *mutex = pthread_mutex_init(&mutex,NULL);
), set it to window (like gr->SetMutex(mutex);
) and periodically check it at calculations (like pthread_mutex_lock(&mutex); pthread_mutex_unlock(&mutex);
).
Finally, you can put the event-handling loop in separate instead of yours code by using RunThr()
function instead of Run()
one. Unfortunately, such method work well only for FLTK windows and only if pthread support was enabled. Such limitation come from the Qt requirement to be run in the primary thread only. The sample code will be:
int main(int argc,char **argv) { mglFLTK gr("test"); gr.RunThr(); // <-- need MathGL version which use pthread for widgets mglPoint pnt; // some data for(int i=0;i<10;i++) // do calculation { long_calculations();// which can be very long pnt.Set(2*mgl_rnd()-1,2*mgl_rnd()-1); gr.Clf(); // make new drawing gr.Line(mglPoint(),pnt,"Ar2"); char str[10] = "i=0"; str[3] = '0'+i; gr->Puts(mglPoint(),str); gr.Update(); // update window } return 0; // finish calculations and close the window }