Reading TFiles within thread (VC++9)

Hi Windows users,
I’m having some problems reading ROOT files in a multithreaded program. My code checks to see if an intermediate file exists and if that file contains necessary trees and creates it if needed. However, the program hangs whenever I try to open that intermediate file, but only under certain conditions.
If I run the algorithm without creating a new thread, it works just fine. However, if I run it within a thread, it hangs if the file exists, independent of the number of threads running. If I try to open the file using the new, create, or recreate options it works fine, but read and update both cause it to hang.

void Analyzer::initFiles(){ const char *rdat=Form("%s.rdat",path); //path to raw data in root format (rdat) FileStat_t stats; if(gSystem->GetPathInfo(rdat,stats)){ //read from raw data (dat) files }else{ TThread::Lock(); //same results with or without lock rawFile=TFile::Open(rdat); //fatal line TThread::UnLock(); if(!rawFile){ //read from dat files }else{ //read from rdat file } } reconFile=TFile::Open(Form("%s.root",path),"recreate"); //works //create recon tree }
Any suggestions?
I’ve tried this with the same results on XP SP3 and Vista Business SP1 with VC++9.00.30729.01 and ROOT 5.22/00. Full code available upon request.
Thanks,
Ben

Hi,

Note that ‘Form’ is using a single static buffer (so all your thread are using the exact same string buffer). Try using:TString rdat; rdat.Form("%s.rdat",path); //path to raw data in root format (rdat) ... reconFile=TFile::Open(TString::Format("%s.root",path),"recreate"); //works

Cheers,
Philippe.

Hi Philippe,
I haven’t had a problem with that (yet) but it’s good to know anyway. Too bad there’s not better documentation on thread safety.
Although it doesn’t solve the big problem.
Thanks,
Ben

Hi,

Can you provide a complete running example showing this problem?

Thanks,
Philippe.

I’ll PM you the link to my code and one of the smaller data files. It’s currently uploading on RapidShare (25MB total).
First, run the makefile.
Second, set RDKANAL=X\Analysis
RDKRAW=X\Raw
RDKHOME=X\Code
Where X is the path the files are extracted to.
Third, run “root tools\login.C” in the RDKHOME folder.
The following code work and overwrite Analysis\ss100\S100r4.root and leave S100r4.rdat intact.

Analyzer *test=new Analyzer(100,4); test->run();
This code, however, will stall after printing “Opening rdat file: S100r4”.

Analyzer *test=new Analyzer(100,4); ThreadRunner *runner=new ThreadRunner("test",(Runnable*)test); runner->run();
Thanks,
Ben
Edit: corrected start instructions.

Hi,

In the thread case, I saw:[code]root [0] .L libRDK.dll
root [1] Analyzer *test=new Analyzer(100,4);
root [2] ThreadRunner runner=new ThreadRunner(“test”,(Runnable)test);
Error in TMutex::UnLock: thread 5088 tries to unlock unlocked mutex
root [3] runner->run();
root [4] Initializing files: S100r4
Stating rdat file: S100r4
rdat file not found: S100r4
Initializing dat reader: S100r4

It looks like the code couldn’t find the rdat file. That could happen if the RDKANAL environmental variable wasn’t set properly. Check those variables and try it again. I suspect it will stop when opening the rdat file.

Hi Philippe,
After some more testing, I think you may be using the debug version of root. I just tested using that version and it fails to find the rdat file even though it does exist. I have no idea why the different versions would behave differently, but you may want to try with the non-debug version.
Thanks,
Ben

Hi,

Indeed my problem was the fact that on Windows one can not mix a debug and optimized build. I was able to recompile your code in debug mode and run. However I also discovered that you use the pattern:const char *tmp = TString::Format(...);This is illegal because TString::Format returns a temporary TString object which is the return (via the const chat* operator) a pointer to its internal buffer. Once the operation is executed, the temporary TString object is deleted and your ‘tmp’ pointer points to random memory (i.e. delete memory).

Once I fixed those issues, I was able to successfully run both the non-thread and thread case. With added printout:[code]$ root.exe -b -l tools/login.C
root [0]
Processing tools/login.C…
root [1] Analyzer *test=new Analyzer(100,4);
root [2] ThreadRunner runner=new ThreadRunner(“test”,(Runnable)test);
Error in TMutex::UnLock: thread 7612 tries to unlock unlocked mutex
root [3] runner->run();
root [4] Initializing files: S100r4
Stating rdat file: S100r4
rdat file found: S100r4
Opening rdat file: S100r4
Initializing rdat reader: S100r4
Initializing dat reader: S100r4
Opening recon file: S100r4
Creating recon tree: S100r4
Branching tree: S100r4
Analyzing files: S100r4
Reading from dat file
Analyzer: 1. Saving file ss100/S100r4.root
Analyzer: 1. Saved file ss100/S100r4.root

root [4] .q
[/code]

Cheers,
Philippe.

Thanks Philippe,
I replaced all of those with TStrings. But it still stalls for me. However, after a lot of experimenting, I think it has something to do with the -b flag. When I run with it, everything works. But without, it hangs at the same spot (opening the rdat file) repeatedly.
Whatever the problem is, it must be in root itself. So I’ll just use that workaround for now.
Thanks again,
Ben

Hi Ben,

I can reproduce the problem without the -b … which is a deadlock type of problem within ROOT … I am investigating.

Cheers,
Philippe.

ROOT with Win32GDK (this is what you use with no -b option and no Qt plugin) is multithreaded application on its own.
It should be taken in account. This fact should be “visible” via Windows debugger. By accident (one needs to see the code to be certain), the different portions of your code can end up within different threads. Please check. Use grep Thread $ROOTSYS/graf2d/win32gdk/src/* grep Thread $ROOTSYS/core/winnt/src/*
to see where the extra threads come from.

Hi Ben,

The problem has been localized and the patch should be in svn soon… Thanks for the report and sorry for the trouble.

Cheers, Bertrand.

Hi Valeri,

[quote=“fine”]Interesting. What was that?[/quote]one extra R__LOCKGUARD2(gROOTMutex); in TThreadTimer::Notify()…

[quote=“fine”]Many thanks for your time and effort.[/quote]You’re most welcome :slight_smile:

Hi,

For info, this has been fixed by revision 28166.

Cheers, Bertrand.