Run TApplication in own thread?

Hello all,

I am wondering if it is possible to (stably!) run a TApplication in it’s own thread. I am acquiring data from a slow source, which I plot as it comes in. I can sort of do this via (please excuse the pseudo-code):

int main(int argc, char** argv){
   TApplication app("app",&argc,argv);
   while( is_running){
       while( !data_ready)
           wait_for_data();
       DrawData();
   }
return 0;
}

The problem with this is that the canvases which pop up are not resizeable, and have no menus and such. While the data acquisition (main) thread is waiting for new data to arrive, I would like to be able to zoom in, resize the canvas, save plots, etc.

I’ve tried opening up a new thread which calls app.Run(), and this seems to do what I want, but there are two big problems. First, the whole process seems to stall even when it’s not handling any input; I assume that the TApplication is not playing nice and releasing the processor slice to the other thread? Also, it randomly crashes and spews out bus errors and segfaults. My completely off the wall guess here is that it is trying to process some event while the objects on the pad are in a state of transition or trying to draw while the canvas is being changed.

So is what I’m trying to do possible? Am I going about it in remotely the right way?

Thanks!
~Ben Loer

here is remote code correction

int main(int argc, char** argv){
TApplication app(“app”,&argc,argv);
while( is_running){
while( !data_ready){
gSystem->Sleep(1); // releases CPU for a period of time
// point is to periodically check if data there
// AND also to check if there are some mouse-clicks on canvases and such
// to save CPU one might increase time of sleep
}
DrawData();
}
return 0;
}

details in TSystem class.
but in general, the following allows to work with canvases while program running:

while(running)
{
if (gSystem->ProcessEvents()){ // checks if there are mouse-clicks on canvases and such
gSystem->Sleep(0); // releases CPU for a period of time. zero simply releases once
}
do_something_in_a_loop();
}

Thanks! This got me pointed in the right direction. One modification which is still needed is the addition of a mutex to make sure that the loop is not trying to ProcessEvents while the objects on a canvas/etc are being updated. Also, ProcessEvents only returns true if there is an interrupt generated, so as you had the code, the process would never sleep, unless I am seeing something wrong. The alterations which worked for me are:

void Process()
{
while(running){
mutex.lock();
if(gSystem->ProcessEvents())
return;
mutex.unlock();
gSystem->Sleep(50);
}
}

int main(int argc, char** argv){
new TApplication(“app”,&argc,argv);
new thread(Process);
while( is_running){
while( !data_ready){
gSystem->Sleep(1); // releases CPU for a period of time
// point is to periodically check if data there
// AND also to check if there are some mouse-clicks on canvases and such
// to save CPU one might increase time of sleep
}
mutex.lock();
DrawData();
mutex.unlock();
}
running=false;
return 0;
}

Thanks again,
~Ben

Check $ROOTSYS/tutorials/thread

In general Let’s call the main ROOT thread “GUI thread”.
Now create a separate thread to collect your data. Let’s call it “Worker thread”.

[code]class Ready :
private:
Bool_t fReady
public:
Ready() : fReady(kFALSE);
SetReady(Bool_t ready = kTRUE) {
// one may want to add the TMutex here
// to be safe
fReady = ready;
}
Bool_t IsReady() {
// one may want to add the TMutex here
// to be safe
Bool_t save = fReady;
fReady = kFALSE; // It is optional. One can use SetReady(kFALSE); instead
return save;
}
};

class myGUI {

private:
Bool_t fkeepUpdating;
static Ready *fReady;

public:
myGUI() : fkeepUpdating(kTRUE) {}

  void SuspendUpdate() {   fkeepUpdating = kFALSE; }
  void ResumeUpdate()  {   fkeepUpdating = kTRUE; updateGui() ;}

 void updateGui() 
 {
     if ((fReady && fReady->IsReady() ) {
         // one may want to add another TMutex here
         // to be safe          
        /// update your view here from your new data
     }
      if (fkeepUpdating) 
         TTimer:SingleShot(500,"myGUI",this,"updateGui()");
 }

};
}[/code]

To fire your GUI loop call myGUI::ResumeUpdate() from “GUI Thread” at once
As soon as your data is ready call Ready::SetReady() from your “Worker”.

In fact, the class Ready is to demonstrate the idea. It is redundant .TMutex::TryLock(), TMutex::Lock(), TMutex::Unlock() can be used directly to provide the same job.

This approach requires no special knowledge about ROOT thread / event / event loop internal implementation. It is suitable for any multithread env (assuming such env provides the “thread”,“mutex” and “singleshot” timer )

Forget to mention :blush:
To implement the above approach one needs no his / her custom “main” ROOT appilcation. The regular ROOT root.cern.ch/viewvc/trunk/main/s … iew=markup will work fine. Just create your own shared library and load it into ROOT session or use ACLiC.

Thank you! A very complete and thorough example =).