TTreeProcessorMT deadlock in ROOT cmd line


ROOT Version: 6.36.02
Platform: linuxx8664gcc
Compiler: g++ (GCC) 14.2.0

Installed with cvmfs, using “source /cvmfs/sft.cern.ch/lcg/views/LCG_108/x86_64-el9-gcc14-opt/setup.sh”

Hi guys,

I am running a code with TTreeProcessorMT and see a strange behavior. The code is

// File: test_multi.C
#include <dirent.h>
#include <functional>

#include "TChain.h"
#include <ROOT/TThreadedObject.hxx>
#include <ROOT/TTreeProcessorMT.hxx>


int test_multi() {
    auto chain = new TChain("SourceTree");
    chain->Add("/path/to/*.root");
    ROOT::EnableThreadSafety();
    auto tp = new ROOT::TTreeProcessorMT(*chain,4);
    auto fillHistogram = [](TTreeReader &reader) {
        // do nothing about the tree but print some info
        std::cout << "begin" <<std::endl;
        std::cout << "end" <<std::endl;
    };
    tp->Process(fillHistogram);
    return 0; 
}
void test_internal()
{
    auto a = test_multi;
    auto b = test_multi;
}

Description: When calling a function that uses TTreeProcessorMT twice from the ROOT interactive command line , and assigning the return value to a variable on each call, the second call deadlocks .

The deadlock only occurs when:

  • Calling from ROOT interactive command line (Cling/CINT)

  • Assigning the return value to a variable (e.g. auto h = test_multi(); )

  • Making two consecutive calls

The deadlock does NOT occur when:

  • First calling

  • Not assigning the return value to a variable (just test_multi(); )

  • Calling with other functions that internally use test_multi() (e.g. test_internal())

  • If the tree is so small that only on cluster is needed to be processed

  • On other ROOT version, I tested 6.24/06, it won’t deadlock

Observed behavior:

  • You need to provide some random tree with lots of entries as “SourceTree“ (1e6 entries maybe)

  • First call: all n-worker threads print their debug messages ( reader / Hist ) and complete successfully

  • Second call: only one worker thread prints “begin” and “end“ , then everything hangs

root [0] .L test_multi.C // load the file
root [1] test_internal(); // calling a function internally invokes test_multi()
root [2] auto a = test_multi(); // first call
root [3] test_multi(); // second call, it's ok if don't assign
root [4] auto b = test_multi(); // second call, this will stuck forever

My guess is that the main thread i.e. the command line compete with the worker threads. Maybe this is a bug?

May be @pcanal can help.