Logo ROOT   6.12/07
Reference Guide
mt201_parallelHistoFill.C
Go to the documentation of this file.
1 /// \file
2 /// \ingroup tutorial_multicore
3 /// \notebook
4 /// Parallel fill of a histogram.
5 /// This tutorial shows how a histogram can be filled in parallel
6 /// with a multithreaded approach. The difference with the multiprocess case,
7 /// see mp201, is that here we cannot count on the copy-on-write mechanism, but
8 /// we rather need to protect the histogram resource with a TThreadedObject
9 /// class. The result of the filling is monitored with the *SnapshotMerge*
10 /// method. This method is not thread safe: in presence of ROOT histograms, the
11 /// system will not crash but the result is not uniquely defined.
12 ///
13 /// \macro_image
14 /// \macro_code
15 ///
16 /// \date January 2016
17 /// \author Danilo Piparo
18 
19 const UInt_t poolSize = 4U;
20 
21 Int_t mt201_parallelHistoFill()
22 {
24 
25  // The concrete histogram instances are created in each thread
26  // lazily, i.e. only if a method is invoked.
27  ROOT::TThreadedObject<TH1F> ts_h("myHist", "Filled in parallel", 128, -8, 8);
28 
29  // The function used to fill the histograms in each thread.
30  auto fillRandomHisto = [&](int seed = 0) {
31  TRandom3 rndm(seed);
32  // IMPORTANT!
33  // It is important to realise that a copy on the stack of the object we
34  // would like to perform operations on is the most efficient way of
35  // accessing it, in particular in presence of a tight loop like the one
36  // below where any overhead put on top of the Fill function call would
37  // have an impact.
38  auto histogram = ts_h.Get();
39  for (auto i : ROOT::TSeqI(1000000)) {
40  histogram->Fill(rndm.Gaus(0, 1));
41  }
42  };
43 
44  // The seeds for the random number generators.
45  auto seeds = ROOT::TSeqI(1, poolSize+1);
46 
47  std::vector<std::thread> pool;
48 
49  // A monitoring thread. This is here only to illustrate the functionality of
50  // the SnapshotMerge method.
51  // It allows "to spy" the multithreaded calculation without the need
52  // of interrupting it.
53  auto monitor = [&]() {
54  for (auto i : ROOT::TSeqI(5)) {
55  std::this_thread::sleep_for(std::chrono::duration<double, std::nano>(500));
56  auto h = ts_h.SnapshotMerge();
57  std::cout << "Entries for the snapshot " << h->GetEntries() << std::endl;
58  }
59  };
60  pool.emplace_back(monitor);
61 
62  // The threads filling the histograms
63  for (auto seed : ROOT::TSeqI(seeds)) {
64  pool.emplace_back(fillRandomHisto, seed);
65  }
66 
67  // Wait for the threads to finish
68  for (auto && t : pool) t.join();
69 
70  // Merge the final result
71  auto sumRandomHisto = ts_h.Merge();
72 
73  std::cout << "Entries for the total sum " << sumRandomHisto->GetEntries() << std::endl;
74 
75  auto c = new TCanvas();
76  sumRandomHisto->DrawClone();
77  return 0;
78 }
Random number generator class based on M.
Definition: TRandom3.h:27
TH1 * h
Definition: legend2.C:5
A wrapper to make object instances thread private, lazily.
int Int_t
Definition: RtypesCore.h:41
unsigned int UInt_t
Definition: RtypesCore.h:42
The Canvas class.
Definition: TCanvas.h:31
void EnableThreadSafety()
Enables the global mutex to make ROOT thread safe/aware.
Definition: TROOT.cxx:528
A pseudo container class which is a generator of indices.
Definition: TSeq.hxx:66
virtual Double_t GetEntries() const
Return the current number of entries.
Definition: TH1.cxx:4178
TSeq< int > TSeqI
Definition: TSeq.hxx:194