{
"cells": [
{
"cell_type": "markdown",
"id": "7f6e1a2b",
"metadata": {},
"source": [
"# mt_fillNtupleFromMultipleThreads\n",
"Fill the same TNtuple from different threads.\n",
"This tutorial illustrates the basics of how it's possible with ROOT\n",
"to write simultaneously to a single output file using TBufferMerger.\n",
"\n",
"\n",
"\n",
"\n",
"**Author:** Guilherme Amadio \n",
"This notebook tutorial was automatically generated with ROOTBOOK-izer from the macro found in the ROOT repository on Tuesday, May 19, 2026 at 08:17 PM."
]
},
{
"cell_type": "markdown",
"id": "a03794f2",
"metadata": {},
"source": [
"Avoid unnecessary output"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "51965759",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:19.234963Z",
"iopub.status.busy": "2026-05-19T20:17:19.234852Z",
"iopub.status.idle": "2026-05-19T20:17:19.554375Z",
"shell.execute_reply": "2026-05-19T20:17:19.553646Z"
}
},
"outputs": [],
"source": [
"gROOT->SetBatch();"
]
},
{
"cell_type": "markdown",
"id": "24b0ce05",
"metadata": {},
"source": [
"Make ROOT thread-safe"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "f45dc461",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:19.556647Z",
"iopub.status.busy": "2026-05-19T20:17:19.556507Z",
"iopub.status.idle": "2026-05-19T20:17:19.761812Z",
"shell.execute_reply": "2026-05-19T20:17:19.761020Z"
}
},
"outputs": [],
"source": [
"ROOT::EnableThreadSafety();"
]
},
{
"cell_type": "markdown",
"id": "709555aa",
"metadata": {},
"source": [
"Total number of events"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "ffe69d73",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:19.763858Z",
"iopub.status.busy": "2026-05-19T20:17:19.763741Z",
"iopub.status.idle": "2026-05-19T20:17:19.969109Z",
"shell.execute_reply": "2026-05-19T20:17:19.968317Z"
}
},
"outputs": [],
"source": [
"const size_t nEntries = 65535;"
]
},
{
"cell_type": "markdown",
"id": "9217a665",
"metadata": {},
"source": [
"Match number of threads to what the hardware can do"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "ce06fef9",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:19.971303Z",
"iopub.status.busy": "2026-05-19T20:17:19.971184Z",
"iopub.status.idle": "2026-05-19T20:17:20.176434Z",
"shell.execute_reply": "2026-05-19T20:17:20.175647Z"
}
},
"outputs": [],
"source": [
"const size_t nWorkers = 4;"
]
},
{
"cell_type": "markdown",
"id": "00f826bb",
"metadata": {},
"source": [
"Split work in equal parts"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "eba14cde",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:20.178333Z",
"iopub.status.busy": "2026-05-19T20:17:20.178215Z",
"iopub.status.idle": "2026-05-19T20:17:20.382372Z",
"shell.execute_reply": "2026-05-19T20:17:20.381550Z"
}
},
"outputs": [],
"source": [
"const size_t nEventsPerWorker = nEntries / nWorkers;"
]
},
{
"cell_type": "markdown",
"id": "21bb8bf9",
"metadata": {},
"source": [
"Create the TBufferMerger: this class orchestrates the parallel writing"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "22496f9a",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:20.384453Z",
"iopub.status.busy": "2026-05-19T20:17:20.384221Z",
"iopub.status.idle": "2026-05-19T20:17:20.589742Z",
"shell.execute_reply": "2026-05-19T20:17:20.588872Z"
}
},
"outputs": [],
"source": [
"auto fileName = \"mt103_fillNtupleFromMultipleThreads.root\";\n",
"ROOT::TBufferMerger merger(fileName);"
]
},
{
"cell_type": "markdown",
"id": "c2b1929b",
"metadata": {},
"source": [
"Define what each worker will do\n",
"We obtain from a merger a TBufferMergerFile, which is nothing more than\n",
"a file which is held in memory and that flushes to the TBufferMerger its\n",
"content."
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "3179a54a",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:20.591624Z",
"iopub.status.busy": "2026-05-19T20:17:20.591486Z",
"iopub.status.idle": "2026-05-19T20:17:20.793963Z",
"shell.execute_reply": "2026-05-19T20:17:20.793180Z"
}
},
"outputs": [],
"source": [
"auto work_function = [&](int seed) {\n",
" auto f = merger.GetFile();\n",
" TNtuple ntrand(\"ntrand\", \"Random Numbers\", \"r\");\n",
"\n",
" TRandom rnd(seed);\n",
" for (auto i : ROOT::TSeqI(nEntries))\n",
" ntrand.Fill(rnd.Gaus());\n",
" f->Write();\n",
"};"
]
},
{
"cell_type": "markdown",
"id": "d0e3e65c",
"metadata": {},
"source": [
"Create worker threads"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "cf6a1f6f",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:20.796252Z",
"iopub.status.busy": "2026-05-19T20:17:20.796130Z",
"iopub.status.idle": "2026-05-19T20:17:21.138405Z",
"shell.execute_reply": "2026-05-19T20:17:21.137640Z"
}
},
"outputs": [],
"source": [
"std::vector workers;\n",
"\n",
"for (auto i : ROOT::TSeqI(nWorkers))\n",
" workers.emplace_back(work_function, i + 1); // seed==0 means random seed :)\n",
"\n",
"// Make sure workers are done\n",
"for (auto &&worker : workers)\n",
" worker.join();"
]
},
{
"cell_type": "markdown",
"id": "c06d6a84",
"metadata": {},
"source": [
"Draw all canvases "
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "7c055de9",
"metadata": {
"collapsed": false,
"execution": {
"iopub.execute_input": "2026-05-19T20:17:21.140455Z",
"iopub.status.busy": "2026-05-19T20:17:21.140331Z",
"iopub.status.idle": "2026-05-19T20:17:21.345726Z",
"shell.execute_reply": "2026-05-19T20:17:21.344826Z"
}
},
"outputs": [],
"source": [
"gROOT->GetListOfCanvases()->Draw()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "ROOT C++",
"language": "c++",
"name": "root"
},
"language_info": {
"codemirror_mode": "text/x-c++src",
"file_extension": ".C",
"mimetype": " text/x-c++src",
"name": "c++"
}
},
"nbformat": 4,
"nbformat_minor": 5
}