RE: [ROOT] ROOT/QtROOT within a multithreaded Qt application

From: Colley, Tony (Tony.Colley@itt.com)
Date: Tue Jan 08 2002 - 15:36:59 MET


Fellow rooters,

I just wanted to provide an update on this issue since one of you may have
to deal with it someday.

To recap quickly, the problem occurred when merging an existing
multithreaded application with ROOT (as a compiled program... I don't know
if the following will work using CINT). In my case, the multithreaded
application used Qt for its GUI.

When one tries to do certain TCanvas operations in a thread different than
the thread which contains the ROOT Event Processing loop (i.e. where the
call to gSystem->DispatchOneEvent is made, in my case this is the main
thread), the program crashes with "***BREAK*** segmentation violation" and
occassionally "<RootX11ErrorHandler>" messages.

My solution is to use mutex locks, thread signals, and global variables to
communicate between the thread which is creating and using the TCanvas and
the ROOT thread, so that certain operations (which crash in a different
thread) are done within the ROOT thread.

For example, when a different thread wants to create a TCanvas it does the
following:

  CALL pthread_mutex_lock to get a "Canvas Request" lock

  WHILE a Canvas Request is pending
    CALL pthread_cond_wait to wait for "Request Idle"
  END WHILE

  Set global variables to specify desired canvas parameters
  Set global flag to indicate "Request Pending"

  WHILE Canvas Request is not filled
    CALL pthread_cond_wait to wait for "Request Filled"
  END WHILE

  Retrieve TCanvas pointer from global variable
  Set global flag to indicate "Request Idle"
  CALL pthread_cond_broadcast to send "Request Idle" signal

  CALL pthread_mutex_unlock to release "Canvas Request" lock


Meanwhile, the ROOT Event Loop (in the main thread) has been modified so
that it does the following before calling DispatchOneEvent:

  IF pthread_mutex_trylock successfully gets a "Canvas Request" lock
    IF a Canvas Request is pending and not filled
      Create a new TCanvas, storing the pointer in a global variable
      Set global flag to indicate "Request Filled"
      CALL pthread_cond_signal to send "Request Filled" signal
    END IF
    CALL pthread_mutex_unlock to release "Canvas Request" lock
  END IF


In order to do what I wanted (create a TCanvas containing some TGraphs), I
had to set up this type of "service" for:
  1. TCanvas creation
  2. calling TCanvas->Update
  3. getting a TAxis pointer using TGraph->GetXaxis and TGraph->GetYaxis

All other TCanvas, TGraph, TAxis calls (that I have tried) can be done
successfully in a working thread (i.e., other than the main thread). Perhaps
I should have simply modified the TCanvas constructors, TCanvas::Update,
TGraph::GetXaxis, and TGraph::GetYaxis to do all this internally (or figured
out why they don't work); but, I have a customer demo tomorrow that I needed
to support and this approach seemed quickest. I may look into that once the
panic level around here drops back to normal.

If anyone is interested in actual source code for these "services", or the
rationale behind my approach, I will be happy to provide it.

Cheers,
Tony Colley

************************************ 
If this email is not intended for you, or you are not responsible for the
delivery of this message to the addressee, please note that this message may
contain ITT Privileged/Proprietary Information.  In such a case, you may not
copy or deliver this message to anyone.  You should destroy this message and
kindly notify the sender by reply email.  Information contained in this
message that does not relate to the business of ITT is neither endorsed by
nor attributable to ITT. 
************************************ 



This archive was generated by hypermail 2b29 : Sat Jan 04 2003 - 23:50:37 MET