Fill the same TNtuple from different threads. This tutorial illustrates the basics of how it's possible with ROOT to write simultaneously to a single output file using TBufferMerger.

This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Sunday, October 02, 2022 at 09:33 AM.

Avoid unnecessary output

In [1]:
gROOT->SetBatch();


In [2]:
ROOT::EnableThreadSafety();


Total number of events

In [3]:
const size_t nEntries = 65535;


Match number of threads to what the hardware can do

In [4]:
const size_t nWorkers = 4;


Split work in equal parts

In [5]:
const size_t nEventsPerWorker = nEntries / nWorkers;


Create the TBufferMerger: this class orchestrates the parallel writing

In [6]:
auto fileName = "mt103_fillNtupleFromMultipleThreads.root";
ROOT::TBufferMerger merger(fileName);


Define what each worker will do We obtain from a merger a TBufferMergerFile, which is nothing more than a file which is held in memory and that flushes to the TBufferMerger its content.

In [7]:
auto work_function = [&](int seed) {
auto f = merger.GetFile();
TNtuple ntrand("ntrand", "Random Numbers", "r");

TRandom rnd(seed);
for (auto i : ROOT::TSeqI(nEntries))
ntrand.Fill(rnd.Gaus());
f->Write();
};


In [8]:
std::vector<std::thread> workers;

for (auto i : ROOT::TSeqI(nWorkers))
workers.emplace_back(work_function, i + 1); // seed==0 means random seed :)

// Make sure workers are done
for (auto &&worker : workers)
worker.join();


Draw all canvases

In [9]:
gROOT->GetListOfCanvases()->Draw()