Question about using ROOT::TThreadedObject<>


Dear Root-experts,

I am trying to understand how to use the ROOT::TThreadedObject<> wrapper, so I was looking at the tutorial mt304_fillHistos.C. The macro in tutorial works if I run it with the interpreter but I could not get it compiled.

What additional headers do I need to include?

/// \file
/// \ingroup tutorial_multicore
/// \notebook -draw
/// Fill histograms in parallel with automatic binning.
/// Illustrates use of power-of-two autobin algorithm
///
/// \macro_code
/// \macro_image
///
/// \date November 2017
/// \author Gerardo Ganis


#include <TROOT.h>
#include <TSystem.h>
#include <TH1.h>
#include <TCanvas.h>
#include <TRandom3.h>
#include <TStyle.h>

// The number of workers
const UInt_t nWorkers = 8U;

// Reference boundaries
const Double_t xmiref = -1.;
const Double_t xmaref = 7.;

Int_t mt304_fillHistos(UInt_t nNumbers = 1001)
{

   // The first, fundamental operation to be performed in order to make ROOT
   // thread-aware.
   ROOT::EnableThreadSafety();

   // Histograms to be filled in parallel
   ROOT::TThreadedObject<TH1D> h1d("h1d", "1D test histogram", 64, 0., -1.);
   ROOT::TThreadedObject<TH1D> h1dr("h1dr", "1D test histogram w/ ref boundaries", 64, xmiref, xmaref);

   // We define our work item
   auto workItem = [&](UInt_t workerID) {
      // One generator, file and ntuple per worker
      TRandom3 workerRndm(workerID); // Change the seed

      auto wh1d = h1d.Get();
      wh1d->SetBit(TH1::kAutoBinPTwo);
      auto wh1dr = h1dr.Get();

      Double_t x;
      for (UInt_t i = 0; i < nNumbers; ++i) {
         x = workerRndm.Gaus(3.);
         wh1d->Fill(x);
         wh1dr->Fill(x);
      }
   };

   // Create the collection which will hold the threads, our "pool"
   std::vector<std::thread> workers;

   // Fill the "pool" with workers
   for (auto workerID : ROOT::TSeqI(nWorkers)) {
      workers.emplace_back(workItem, workerID);
   }

   // Now join them
   for (auto &&worker : workers)
      worker.join();

   // Merge
   auto fh1d = h1d.Merge();
   auto fh1dr = h1dr.Merge();

   // Make the canvas
   auto c = new TCanvas("c", "c", 800, 800);
   c->Divide(1, 2);

   gStyle->SetOptStat(111110);
   c->cd(1);
   fh1d->DrawCopy();
   c->cd(2);
   fh1dr->DrawCopy();

   c->Update();

   return 0;
}

I get the following errors:

   ------------------------------------------------------------------
  | Welcome to ROOT 6.34.04                        https://root.cern |
  | (c) 1995-2024, The ROOT Team; conception: R. Brun, F. Rademakers |
  | Built for win64 on Feb 10 2025, 12:25:15                         |
  | From tags/v6-34-04@v6-34-04                                      |
  | With MSVC 19.39.33521.0                                          |
  | Try '.help'/'.?', '.demo', '.license', '.credits', '.quit'/'.q'  |
   ------------------------------------------------------------------

root [0] .L mt304_fillHistos.C+
Info in <TWinNTSystem::ACLiC>: creating shared library D:/Multicore/mt304_fillHistos_C.dll
In file included from input_line_9:9:
.\mt304_fillHistos.C:36:10: error: no member named 'TThreadedObject' in namespace 'ROOT'
   ROOT::TThreadedObject<TH1D> h1d("h1d", "1D test histogram", 64, 0., -1.);
   ~~~~~~^
.\mt304_fillHistos.C:36:26: error: 'TH1D' does not refer to a value
   ROOT::TThreadedObject<TH1D> h1d("h1d", "1D test histogram", 64, 0., -1.);
                         ^
D:/ROOT/include\TH1.h:670:7: note: declared here
class TH1D : public TH1, public TArrayD {
      ^
In file included from input_line_9:9:
.\mt304_fillHistos.C:36:32: error: use of undeclared identifier 'h1d'
   ROOT::TThreadedObject<TH1D> h1d("h1d", "1D test histogram", 64, 0., -1.);
                               ^
.\mt304_fillHistos.C:37:10: error: no member named 'TThreadedObject' in namespace 'ROOT'
   ROOT::TThreadedObject<TH1D> h1dr("h1dr", "1D test histogram w/ ref boundaries", 64, xmiref, xmaref);
   ~~~~~~^
.\mt304_fillHistos.C:37:26: error: 'TH1D' does not refer to a value
   ROOT::TThreadedObject<TH1D> h1dr("h1dr", "1D test histogram w/ ref boundaries", 64, xmiref, xmaref);
                         ^
D:/ROOT/include\TH1.h:670:7: note: declared here
class TH1D : public TH1, public TArrayD {
      ^
In file included from input_line_9:9:
.\mt304_fillHistos.C:37:32: error: use of undeclared identifier 'h1dr'
   ROOT::TThreadedObject<TH1D> h1dr("h1dr", "1D test histogram w/ ref boundaries", 64, xmiref, xmaref);
                               ^
.\mt304_fillHistos.C:44:19: error: use of undeclared identifier 'h1d'
      auto wh1d = h1d.Get();
                  ^
.\mt304_fillHistos.C:46:20: error: use of undeclared identifier 'h1dr'
      auto wh1dr = h1dr.Get();
                   ^
.\mt304_fillHistos.C:57:21: error: no member named 'thread' in namespace 'std'
   std::vector<std::thread> workers;
               ~~~~~^
.\mt304_fillHistos.C:60:31: error: no member named 'TSeqI' in namespace 'ROOT'
   for (auto workerID : ROOT::TSeqI(nWorkers)) {
                        ~~~~~~^
.\mt304_fillHistos.C:69:16: error: use of undeclared identifier 'h1d'
   auto fh1d = h1d.Merge();
               ^
.\mt304_fillHistos.C:70:17: error: use of undeclared identifier 'h1dr'
   auto fh1dr = h1dr.Merge();
                ^
Error: D:\ROOT\bin\rootcling: compilation failure (D:\Multicore/mt304_fillHistos_C_ACLiC_dict856d544eba_dictUmbrella.h)
Error in <ACLiC>: Executing 'D:\ROOT\bin\rootcling "--lib-list-prefix=D:\Multicore\mt304_fillHistos_C_ACLiC_map" -f "D:\Multicore\mt304_fillHistos_C_ACLiC_dict.cxx"  -rml mt304_fillHistos_C -rmf "D:\Multicore\mt304_fillHistos_C.rootmap" -DR__ACLIC_ROOTMAP -I%ROOTSYS%\include -D__ACLIC__  "D:/Multicore/mt304_fillHistos.C" "D:\Multicore\mt304_fillHistos_C_ACLiC_linkdef.h"' failed!

Your help is much appreciated!

Add these lines:

#include "ROOT/TThreadedObject.hxx"
#include "ROOT/TSeq.hxx"

Then it works:

C:\root-dev\rootdev>root -l mt304_fillHistos.cxx+
root [0]
Processing mt304_fillHistos.cxx+...
Info in <TWinNTSystem::ACLiC>: creating shared library C:/root-dev/rootdev/mt304_fillHistos_cxx.dll
mt304_fillHistos_cxx_ACLiC_dict.cxx
   Creating library C:/root-dev/rootdev\mt304_fillHistos_cxx.lib and object C:/root-dev/rootdev\mt304_fillHistos_cxx.exp
mt304_fillHistos_cxx_ACLiC_dict.cxx
   Creating library C:/root-dev/rootdev\mt304_fillHistos_cxx.lib and object C:/root-dev/rootdev\mt304_fillHistos_cxx.exp
(int) 0
root [1] .q

Many thanks for the quick reply!

It works now, indeed.

1 Like