{ "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 }