Reading and opening TFiles in parallel

Hello,
I have found several threads somewhat touching on this issue, but they all seem to be either a bit old or concerned with writing. I’m sorry if this is already answered elsewhere, but I didn’t find it. I’m using ROOT6 but having this work on ROOT5 as well would be a bonus.

I have many files with TTrees in them. I would like to have ~4 IO threads each working on one unique file. Once an event is read, the thread is sending the read object to a consumer thread. Once an IO thread is done with its file, its fetching and opening another one. I am making sure that the actual call to TFile::Open is not executing twice in parallel. However, TFile::Open might still be called while other other threads are reading from an already opened file.

For most parts this is working pretty well, but I am getting mysterious crashes every now and then. From reading other threads here on the forum I got the impression that I have to “freeze the world” when calling TFile::Open to make sure nothing is happening in parallel. Is that assumption correct? Must I not read any other file/TTree in a parallel thread while opening a new file?

Thanks!
Christian

Example stack trace of a crash:

#0  0x00007ffff5f3e1bc in TIter::TIter (dir=true, col=0x7ffd3ff2c400, this=<synthetic pointer>) at /home/christian/repos/root6/build/include/TCollection.h:147
#1  TFile::ReadStreamerInfo (this=0x7ffcf45e8100) at /home/christian/repos/root6/root/io/io/src/TFile.cxx:3461
#2  0x00007ffff5f47f0c in TFile::Init (this=this@entry=0x7ffcf45e8100, create=create@entry=false) at /home/christian/repos/root6/root/io/io/src/TFile.cxx:854
#3  0x00007ffff5f49350 in TFile::TFile (this=0x7ffcf45e8100, fname1=<optimized out>, option=<optimized out>, ftitle=<optimized out>, compress=<optimized out>)
    at /home/christian/repos/root6/root/io/io/src/TFile.cxx:519
#4  0x00007ffff5f4da9a in TFile::Open (url=<optimized out>, options=<optimized out>, ftitle=0x5555556cbd0e "", compress=1, netopt=0) at /home/christian/repos/root6/root/io/io/src/TFile.cxx:4068
#5  0x00005555555c1b3a in ESD_t::ESD_t(char const*) ()
#6  0x00005555555c20a1 in esd_new ()
#7  0x00005555555a0cb2 in alice::esd::ESD::new::hd419fa5c6e6dbe1d ()
#8  0x000055555556ffa0 in std::panicking::try::do_call::h714ca5963b39388c ()
#9  0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#10 0x000055555557365d in _$LT$rayon_core..job..HeapJob$LT$BODY$GT$$u20$as$u20$rayon_core..job..Job$GT$::execute::h34704fae5448c15b ()
#11 0x00005555555ab245 in rayon_core::registry::WorkerThread::wait_until_cold::h0a49f749faaf045e ()
#12 0x00005555555ab94f in rayon_core::registry::main_loop::h2c8ea8413be39dec ()
#13 0x00005555555a8d38 in _$LT$std..panic..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$::call_once::h917620e1800c7f69 ()
#14 0x00005555555a4e98 in std::panicking::try::do_call::hbbd459a5a4e43e7b ()
#15 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#16 0x00005555555a4e3f in std::panicking::try::h95b306b6eac264b9 ()
#17 0x00005555555a8dbc in std::panic::catch_unwind::h8d1ba6569c31084a ()
#18 0x00005555555a5f28 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::h53cefb9fd246f329 ()
#19 0x000055555566967c in alloc::boxed::{{impl}}::call_once<(),()> () at /checkout/src/liballoc/boxed.rs:692
#20 std::sys_common::thread::start_thread () at /checkout/src/libstd/sys_common/thread.rs:21
#21 std::sys::imp::thread::{{impl}}::new::thread_start () at /checkout/src/libstd/sys/unix/thread.rs:84
#22 0x00007ffff68776ba in start_thread (arg=0x7ffff39be700) at pthread_create.c:333
#23 0x00007ffff6d983dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

which happened while other threads where reading other files. (I’m calling ROOT through a C-FFI)

Hi,
we routinely call TFile::Open concurrently in TDataFrame (which by the way offers transparent multi-thread reading and writing precisely so that users don’t have to write it themselves :slight_smile: ).

@pcanal can confirm with more authority than me, but the main thing you must take care of is that different threads use different TFile objects. Are you calling ROOT::EnableThreadSafety at the start of your application?

On the other hand ROOT still suffers from thread-unsafe construction and deletion of certain types of objects (such as TTree and TH1) that at construction and destruction are registered and de-registered from global lists (e.g. gListOfCleanups) in an unsafe way.

Will edit soon with a small proof of concept that TFile::Open is thread-safe for your kind of usage.

EDIT:
this works:

#include "TFile.h"
#include "TH1F.h"
#include "TROOT.h"
#include <thread>

int main() {
   ROOT::EnableThreadSafety();

   // write a file containing a TH1
   TFile f("f.root", "RECREATE");
   TH1F h("h","h",100,-1,1);
   h.FillRandom("gaus", 100);
   h.Write();
   f.Close();

   // read it from multiple threads with different `TFile` objects
   auto readHisto = []() {
      std::unique_ptr<TFile> f(TFile::Open("f.root"));
      TH1F *h = nullptr;
      f->GetObject("h", h);
      if (h->GetEntries() != 100)
         throw;
   };
   std::vector<std::thread> threads;
   const auto nThreads = 8u;
   threads.reserve(nThreads);
   while (true) {
      for (auto i = 0u; i < nThreads; ++i)
         threads.emplace_back(readHisto);
      for (auto i = 0u; i < nThreads; ++i)
         threads[i].join();
      threads.clear();
   }
}

Cheers,
Enrico

Thanks for your reply! I am a bit confused why your example would work with TH1. My understanding would be that everything that has a name might cause problems? In may case, I am opening files with TTrees (to be precise, its the ALICE Open Data ESDs.). I can’t seem to pinpoint exactly when the crashes happen, but it always seem to occur while several threads call TBranch::GetEntry. Looking at a backtrace now, it seems like all 4 threads where in that function. Two were dealing with TStrings, one with TObjArray and one is not quite clear.

So I guess the question is what makes your example work, even though it uses a nameed object?

P.S. Here is the backtrace of the 4 threads. Thread 4 crashed.
Edit: I just notice that I probably did not run with ROOT::EnableThreadSafty()! So this might be a mute point! But the question remains: Why would it work with histograms which have names?

(gdb) thread 2
[Switching to thread 2 (Thread 0x7ffff3bbf700 (LWP 12827))]
#0  operator== (s1=..., s2=s2@entry=0x7ffff60e476e "TDirectory") at /home/christian/repos/root6/root/core/base/src/TString.cxx:1396
1396	   for (i = 0; s2[i]; ++i)
(gdb) backtrace 
#0  operator== (s1=..., s2=s2@entry=0x7ffff60e476e "TDirectory") at /home/christian/repos/root6/root/core/base/src/TString.cxx:1396
#1  0x00007ffff5f2df55 in TKey::Streamer (this=this@entry=0x7ffcf6b5d000, b=...) at /home/christian/repos/root6/root/io/io/src/TKey.cxx:1380
#2  0x00007ffff7b8a8af in TBasket::Streamer (this=0x7ffcf6b5d000, b=...) at /home/christian/repos/root6/root/tree/tree/src/TBasket.cxx:773
#3  0x00007ffff7b89905 in TBasket::ReadBasketBuffers (this=this@entry=0x7ffcf6b5d000, pos=350486765, len=118, file=file@entry=0x7ffcfcc47f00)
    at /home/christian/repos/root6/root/tree/tree/src/TBasket.cxx:518
#4  0x00007ffff7b44796 in TBranch::GetBasket (this=this@entry=0x7ffff3756400, basketnumber=6) at /home/christian/repos/root6/root/tree/tree/src/TBranch.cxx:1149
#5  0x00007ffff7b44da3 in TBranch::GetEntry (this=this@entry=0x7ffff3756400, entry=entry@entry=156, getall=getall@entry=0) at /home/christian/repos/root6/root/tree/tree/src/TBranch.cxx:1275
#6  0x00007ffff7b74440 in TBranchElement::GetEntry (this=0x7ffff3756400, entry=156, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2332
#7  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffff3756800, entry=156, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#8  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffff3739400, entry=156, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#9  0x00007ffff7b5c2ea in TTree::<lambda()>::operator() (__closure=<synthetic pointer>) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5342
#10 TTree::GetEntry (this=0x7ffff36d9000, entry=156, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5416
#11 0x00005555555a0d19 in alice::esd::ESD::load_event::hc0199e029a7e9ce1 ()
#12 0x000055555556ffff in std::panicking::try::do_call::h714ca5963b39388c ()
#13 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#14 0x000055555557365d in _$LT$rayon_core..job..HeapJob$LT$BODY$GT$$u20$as$u20$rayon_core..job..Job$GT$::execute::h34704fae5448c15b ()
#15 0x00005555555ab245 in rayon_core::registry::WorkerThread::wait_until_cold::h0a49f749faaf045e ()
#16 0x00005555555ab94f in rayon_core::registry::main_loop::h2c8ea8413be39dec ()
#17 0x00005555555a8d38 in _$LT$std..panic..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$::call_once::h917620e1800c7f69 ()
#18 0x00005555555a4e98 in std::panicking::try::do_call::hbbd459a5a4e43e7b ()
#19 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#20 0x00005555555a4e3f in std::panicking::try::h95b306b6eac264b9 ()
#21 0x00005555555a8dbc in std::panic::catch_unwind::h8d1ba6569c31084a ()
#22 0x00005555555a5f28 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::h53cefb9fd246f329 ()
#23 0x000055555566967c in alloc::boxed::{{impl}}::call_once<(),()> () at /checkout/src/liballoc/boxed.rs:692
#24 std::sys_common::thread::start_thread () at /checkout/src/libstd/sys_common/thread.rs:21
#25 std::sys::imp::thread::{{impl}}::new::thread_start () at /checkout/src/libstd/sys/unix/thread.rs:84
#26 0x00007ffff68776ba in start_thread (arg=0x7ffff3bbf700) at pthread_create.c:333
#27 0x00007ffff6d983dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) thread 3
[Switching to thread 3 (Thread 0x7ffff35ff700 (LWP 12828))]
#0  TObjArray::AddAt (this=0x7ffcf73a1140, obj=0x7ffd37050000, idx=37) at /home/christian/repos/root6/root/core/cont/src/TObjArray.cxx:240
240	{
(gdb) backtrace 
#0  TObjArray::AddAt (this=0x7ffcf73a1140, obj=0x7ffd37050000, idx=37) at /home/christian/repos/root6/root/core/cont/src/TObjArray.cxx:240
#1  0x00007ffff7b44964 in TBranch::GetBasket (this=this@entry=0x7ffcf73a1000, basketnumber=37) at /home/christian/repos/root6/root/tree/tree/src/TBranch.cxx:1170
#2  0x00007ffff7b44da3 in TBranch::GetEntry (this=this@entry=0x7ffcf73a1000, entry=entry@entry=190, getall=getall@entry=0) at /home/christian/repos/root6/root/tree/tree/src/TBranch.cxx:1275
#3  0x00007ffff7b74440 in TBranchElement::GetEntry (this=0x7ffcf73a1000, entry=190, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2332
#4  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffcf31ffc00, entry=190, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#5  0x00007ffff7b5c2ea in TTree::<lambda()>::operator() (__closure=<synthetic pointer>) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5342
#6  TTree::GetEntry (this=0x7ffff30d9000, entry=190, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5416
#7  0x00005555555a0d19 in alice::esd::ESD::load_event::hc0199e029a7e9ce1 ()
#8  0x000055555556ffff in std::panicking::try::do_call::h714ca5963b39388c ()
#9  0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#10 0x000055555557365d in _$LT$rayon_core..job..HeapJob$LT$BODY$GT$$u20$as$u20$rayon_core..job..Job$GT$::execute::h34704fae5448c15b ()
#11 0x00005555555ab245 in rayon_core::registry::WorkerThread::wait_until_cold::h0a49f749faaf045e ()
#12 0x00005555555ab94f in rayon_core::registry::main_loop::h2c8ea8413be39dec ()
#13 0x00005555555a8d38 in _$LT$std..panic..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$::call_once::h917620e1800c7f69 ()
#14 0x00005555555a4e98 in std::panicking::try::do_call::hbbd459a5a4e43e7b ()
#15 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#16 0x00005555555a4e3f in std::panicking::try::h95b306b6eac264b9 ()
#17 0x00005555555a8dbc in std::panic::catch_unwind::h8d1ba6569c31084a ()
#18 0x00005555555a5f28 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::h53cefb9fd246f329 ()
#19 0x000055555566967c in alloc::boxed::{{impl}}::call_once<(),()> () at /checkout/src/liballoc/boxed.rs:692
#20 std::sys_common::thread::start_thread () at /checkout/src/libstd/sys_common/thread.rs:21
#21 std::sys::imp::thread::{{impl}}::new::thread_start () at /checkout/src/libstd/sys/unix/thread.rs:84
#22 0x00007ffff68776ba in start_thread (arg=0x7ffff35ff700) at pthread_create.c:333
#23 0x00007ffff6d983dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) thread 4
[Switching to thread 4 (Thread 0x7ffff2fff700 (LWP 12829))]
#0  0x0000000100000000 in ?? ()
(gdb) backtrace 
#0  0x0000000100000000 in ?? ()
#1  0x00007ffff5ff2cb5 in TStreamerInfoActions::TConfiguredAction::operator() (this=<optimized out>, this=<optimized out>, object=0x7ffd2f8391bc, buffer=...)
    at /home/christian/repos/root6/build/include/TStreamerInfoActions.h:116
#2  TBufferFile::ApplySequence (this=0x7ffcd662e5a0, sequence=..., obj=0x7ffd2f8391bc) at /home/christian/repos/root6/root/io/io/src/TBufferFile.cxx:4015
#3  0x00007ffff7b7660c in TBranchElement::ReadLeavesMakeClass (this=0x7ffcfbfe5000, b=...) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:3724
#4  0x00007ffff7b44bc6 in TBranch::GetEntry (this=this@entry=0x7ffcfbfe5000, entry=entry@entry=0, getall=getall@entry=0) at /home/christian/repos/root6/root/tree/tree/src/TBranch.cxx:1317
#5  0x00007ffff7b74440 in TBranchElement::GetEntry (this=0x7ffcfbfe5000, entry=0, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2332
#6  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffcfbbffc00, entry=0, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#7  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffcfbbff800, entry=0, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#8  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffcfbbff400, entry=0, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#9  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffcfbbff000, entry=0, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#10 0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffcfbbe0c00, entry=0, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#11 0x00007ffff7b5c2ea in TTree::<lambda()>::operator() (__closure=<synthetic pointer>) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5342
#12 TTree::GetEntry (this=0x7ffff28d9000, entry=0, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5416
#13 0x00005555555a0d19 in alice::esd::ESD::load_event::hc0199e029a7e9ce1 ()
#14 0x000055555556ffff in std::panicking::try::do_call::h714ca5963b39388c ()
#15 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#16 0x000055555557365d in _$LT$rayon_core..job..HeapJob$LT$BODY$GT$$u20$as$u20$rayon_core..job..Job$GT$::execute::h34704fae5448c15b ()
#17 0x00005555555ab245 in rayon_core::registry::WorkerThread::wait_until_cold::h0a49f749faaf045e ()
#18 0x00005555555ab94f in rayon_core::registry::main_loop::h2c8ea8413be39dec ()
#19 0x00005555555a8d38 in _$LT$std..panic..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$::call_once::h917620e1800c7f69 ()
#20 0x00005555555a4e98 in std::panicking::try::do_call::hbbd459a5a4e43e7b ()
#21 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#22 0x00005555555a4e3f in std::panicking::try::h95b306b6eac264b9 ()
#23 0x00005555555a8dbc in std::panic::catch_unwind::h8d1ba6569c31084a ()
#24 0x00005555555a5f28 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::h53cefb9fd246f329 ()
#25 0x000055555566967c in alloc::boxed::{{impl}}::call_once<(),()> () at /checkout/src/liballoc/boxed.rs:692
#26 std::sys_common::thread::start_thread () at /checkout/src/libstd/sys_common/thread.rs:21
#27 std::sys::imp::thread::{{impl}}::new::thread_start () at /checkout/src/libstd/sys/unix/thread.rs:84
#28 0x00007ffff68776ba in start_thread (arg=0x7ffff2fff700) at pthread_create.c:333
#29 0x00007ffff6d983dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109
(gdb) thread 5
[Switching to thread 5 (Thread 0x7ffff2dfe700 (LWP 12830))]
#0  operator== (s1=..., s2=s2@entry=0x7ffff60e476e "TDirectory") at /home/christian/repos/root6/root/core/base/src/TString.cxx:1396
1396	   for (i = 0; s2[i]; ++i)
(gdb) backtrace 
#0  operator== (s1=..., s2=s2@entry=0x7ffff60e476e "TDirectory") at /home/christian/repos/root6/root/core/base/src/TString.cxx:1396
#1  0x00007ffff5f2df55 in TKey::Streamer (this=this@entry=0x7ffd0427c700, b=...) at /home/christian/repos/root6/root/io/io/src/TKey.cxx:1380
#2  0x00007ffff7b8a8af in TBasket::Streamer (this=0x7ffd0427c700, b=...) at /home/christian/repos/root6/root/tree/tree/src/TBasket.cxx:773
#3  0x00007ffff7b89905 in TBasket::ReadBasketBuffers (this=this@entry=0x7ffd0427c700, pos=85495508, len=1277141, file=file@entry=0x7ffd04b04b80)
    at /home/christian/repos/root6/root/tree/tree/src/TBasket.cxx:518
#4  0x00007ffff7b44796 in TBranch::GetBasket (this=this@entry=0x7ffd043ff800, basketnumber=15) at /home/christian/repos/root6/root/tree/tree/src/TBranch.cxx:1149
#5  0x00007ffff7b44da3 in TBranch::GetEntry (this=this@entry=0x7ffd043ff800, entry=entry@entry=44, getall=getall@entry=0) at /home/christian/repos/root6/root/tree/tree/src/TBranch.cxx:1275
#6  0x00007ffff7b74440 in TBranchElement::GetEntry (this=0x7ffd043ff800, entry=44, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2332
#7  0x00007ffff7b743e5 in TBranchElement::GetEntry (this=0x7ffd043ed000, entry=44, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TBranchElement.cxx:2315
#8  0x00007ffff7b5c2ea in TTree::<lambda()>::operator() (__closure=<synthetic pointer>) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5342
#9  TTree::GetEntry (this=0x7ffd56079b00, entry=44, getall=0) at /home/christian/repos/root6/root/tree/tree/src/TTree.cxx:5416
#10 0x00005555555a0d19 in alice::esd::ESD::load_event::hc0199e029a7e9ce1 ()
#11 0x000055555556ffff in std::panicking::try::do_call::h714ca5963b39388c ()
#12 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#13 0x000055555557365d in _$LT$rayon_core..job..HeapJob$LT$BODY$GT$$u20$as$u20$rayon_core..job..Job$GT$::execute::h34704fae5448c15b ()
#14 0x00005555555ab245 in rayon_core::registry::WorkerThread::wait_until_cold::h0a49f749faaf045e ()
#15 0x00005555555ab94f in rayon_core::registry::main_loop::h2c8ea8413be39dec ()
#16 0x00005555555a8d38 in _$LT$std..panic..AssertUnwindSafe$LT$F$GT$$u20$as$u20$core..ops..function..FnOnce$LT$$LP$$RP$$GT$$GT$::call_once::h917620e1800c7f69 ()
#17 0x00005555555a4e98 in std::panicking::try::do_call::hbbd459a5a4e43e7b ()
#18 0x000055555567168d in panic_unwind::__rust_maybe_catch_panic () at /checkout/src/libpanic_unwind/lib.rs:98
#19 0x00005555555a4e3f in std::panicking::try::h95b306b6eac264b9 ()
#20 0x00005555555a8dbc in std::panic::catch_unwind::h8d1ba6569c31084a ()
#21 0x00005555555a5f28 in _$LT$F$u20$as$u20$alloc..boxed..FnBox$LT$A$GT$$GT$::call_box::h53cefb9fd246f329 ()
#22 0x000055555566967c in alloc::boxed::{{impl}}::call_once<(),()> () at /checkout/src/liballoc/boxed.rs:692
#23 std::sys_common::thread::start_thread () at /checkout/src/libstd/sys_common/thread.rs:21
#24 std::sys::imp::thread::{{impl}}::new::thread_start () at /checkout/src/libstd/sys/unix/thread.rs:84
#25 0x00007ffff68776ba in start_thread (arg=0x7ffff2dfe700) at pthread_create.c:333
#26 0x00007ffff6d983dd in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109

Alright I should not have used a TH1F in my example right after saying they might be unsafe xD

The thing is, thread-unsafety is not related to names, but to concurrent registration/de-registration in gListOfCleanups, which depends on the somewhat convoluted rules of ROOT ownership (there’s a section of the user’s guide dedicated to those rules). Reading a TH1F from a file evidently does not register the TH1F in that global list, as it is owned by the TFile itself.

In general, reading objects from different TFiles concurrently should be safe as long as you have enabled thread-safety. Can you confirm that solves your issue?

Hi again,

Indeed, calling ROOT::EnableThreadSafty() before going multithreaded seemed to have solved the issue. Or at least I’m not seeing crashes anymore :wink: Thanks a lot for the clarifications!

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.